--- a/net/minecraft/world/entity/npc/Villager.java
+++ b/net/minecraft/world/entity/npc/Villager.java
@@ -9,8 +9,10 @@
 import com.mojang.serialization.DataResult;
 import com.mojang.serialization.Dynamic;
 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.BiPredicate;
@@ -88,13 +90,21 @@
 import net.minecraft.world.phys.AABB;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.v1_19_R1.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityTransformEvent;
+import org.bukkit.event.entity.VillagerReplenishTradeEvent;
+// CraftBukkit end
+
 public class Villager extends AbstractVillager implements ReputationEventHandler, VillagerDataHolder {
+
     private static final Logger LOGGER = LogUtils.getLogger();
     private static final EntityDataAccessor<VillagerData> DATA_VILLAGER_DATA = SynchedEntityData.defineId(Villager.class, EntityDataSerializers.VILLAGER_DATA);
     public static final int BREEDING_FOOD_THRESHOLD = 12;
     public static final Map<Item, Integer> FOOD_POINTS = ImmutableMap.of(Items.BREAD, 4, Items.POTATO, 1, Items.CARROT, 1, Items.BEETROOT, 1);
     private static final int TRADES_PER_LEVEL = 2;
-    private static final Set<Item> WANTED_ITEMS = ImmutableSet.of(Items.BREAD, Items.POTATO, Items.CARROT, Items.WHEAT, Items.WHEAT_SEEDS, Items.BEETROOT, Items.BEETROOT_SEEDS);
+    private static final Set<Item> WANTED_ITEMS = ImmutableSet.of(Items.BREAD, Items.POTATO, Items.CARROT, Items.WHEAT, Items.WHEAT_SEEDS, Items.BEETROOT, new Item[]{Items.BEETROOT_SEEDS});
     private static final int MAX_GOSSIP_TOPICS = 10;
     private static final int GOSSIP_COOLDOWN = 1200;
     private static final int GOSSIP_DECAY_INTERVAL = 24000;
@@ -110,7 +120,7 @@
     private Player lastTradedPlayer;
     private boolean chasing;
     private int foodLevel;
-    private final GossipContainer gossips = new GossipContainer();
+    private final GossipContainer gossips;
     private long lastGossipTime;
     private long lastGossipDecayTime;
     private int villagerXp;
@@ -118,15 +128,15 @@
     public int numberOfRestocksToday;
     private long lastRestockCheckDayTime;
     private boolean assignProfessionWhenSpawned;
-    private static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.HOME, MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, MemoryModuleType.MEETING_POINT, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.VISIBLE_VILLAGER_BABIES, MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.WALK_TARGET, MemoryModuleType.LOOK_TARGET, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.BREED_TARGET, MemoryModuleType.PATH, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_BED, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.NEAREST_HOSTILE, MemoryModuleType.SECONDARY_JOB_SITE, MemoryModuleType.HIDING_PLACE, MemoryModuleType.HEARD_BELL_TIME, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.LAST_SLEPT, MemoryModuleType.LAST_WOKEN, MemoryModuleType.LAST_WORKED_AT_POI, MemoryModuleType.GOLEM_DETECTED_RECENTLY);
+    private static final ImmutableList<MemoryModuleType<?>> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.HOME, MemoryModuleType.JOB_SITE, MemoryModuleType.POTENTIAL_JOB_SITE, MemoryModuleType.MEETING_POINT, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.VISIBLE_VILLAGER_BABIES, MemoryModuleType.NEAREST_PLAYERS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.WALK_TARGET, new MemoryModuleType[]{MemoryModuleType.LOOK_TARGET, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.BREED_TARGET, MemoryModuleType.PATH, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_BED, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.NEAREST_HOSTILE, MemoryModuleType.SECONDARY_JOB_SITE, MemoryModuleType.HIDING_PLACE, MemoryModuleType.HEARD_BELL_TIME, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.LAST_SLEPT, MemoryModuleType.LAST_WOKEN, MemoryModuleType.LAST_WORKED_AT_POI, MemoryModuleType.GOLEM_DETECTED_RECENTLY});
     private static final ImmutableList<SensorType<? extends Sensor<? super Villager>>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.NEAREST_ITEMS, SensorType.NEAREST_BED, SensorType.HURT_BY, SensorType.VILLAGER_HOSTILES, SensorType.VILLAGER_BABIES, SensorType.SECONDARY_POIS, SensorType.GOLEM_DETECTED);
-    public static final Map<MemoryModuleType<GlobalPos>, BiPredicate<Villager, Holder<PoiType>>> POI_MEMORIES = ImmutableMap.of(MemoryModuleType.HOME, (villager, holder) -> {
+    public static final Map<MemoryModuleType<GlobalPos>, BiPredicate<Villager, Holder<PoiType>>> POI_MEMORIES = ImmutableMap.of(MemoryModuleType.HOME, (entityvillager, holder) -> {
         return holder.is(PoiTypes.HOME);
-    }, MemoryModuleType.JOB_SITE, (villager, holder) -> {
-        return villager.getVillagerData().getProfession().heldJobSite().test(holder);
-    }, MemoryModuleType.POTENTIAL_JOB_SITE, (villager, holder) -> {
+    }, MemoryModuleType.JOB_SITE, (entityvillager, holder) -> {
+        return entityvillager.getVillagerData().getProfession().heldJobSite().test(holder);
+    }, MemoryModuleType.POTENTIAL_JOB_SITE, (entityvillager, holder) -> {
         return VillagerProfession.ALL_ACQUIRABLE_JOBS.test(holder);
-    }, MemoryModuleType.MEETING_POINT, (villager, holder) -> {
+    }, MemoryModuleType.MEETING_POINT, (entityvillager, holder) -> {
         return holder.is(PoiTypes.MEETING);
     });
 
@@ -136,7 +146,8 @@
 
     public Villager(EntityType<? extends Villager> entityType, Level world, VillagerType type) {
         super(entityType, world);
-        ((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(true);
+        this.gossips = new GossipContainer();
+        ((GroundPathNavigation) this.getNavigation()).setCanOpenDoors(true);
         this.getNavigation().setCanFloat(true);
         this.setCanPickUpLoot(true);
         this.setVillagerData(this.getVillagerData().setType(type).setProfession(VillagerProfession.NONE));
@@ -144,46 +155,49 @@
 
     @Override
     public Brain<Villager> getBrain() {
-        return super.getBrain();
+        return (Brain<Villager>) super.getBrain(); // CraftBukkit - decompile error
     }
 
     @Override
     protected Brain.Provider<Villager> brainProvider() {
-        return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
+        return Brain.provider(Villager.MEMORY_TYPES, Villager.SENSOR_TYPES);
     }
 
     @Override
     protected Brain<?> makeBrain(Dynamic<?> dynamic) {
-        Brain<Villager> brain = this.brainProvider().makeBrain(dynamic);
-        this.registerBrainGoals(brain);
-        return brain;
+        Brain<Villager> behaviorcontroller = this.brainProvider().makeBrain(dynamic);
+
+        this.registerBrainGoals(behaviorcontroller);
+        return behaviorcontroller;
     }
 
     public void refreshBrain(ServerLevel world) {
-        Brain<Villager> brain = this.getBrain();
-        brain.stopAll(world, this);
-        this.brain = brain.copyWithoutBehaviors();
+        Brain<Villager> behaviorcontroller = this.getBrain();
+
+        behaviorcontroller.stopAll(world, this);
+        this.brain = behaviorcontroller.copyWithoutBehaviors();
         this.registerBrainGoals(this.getBrain());
     }
 
     private void registerBrainGoals(Brain<Villager> brain) {
-        VillagerProfession villagerProfession = this.getVillagerData().getProfession();
+        VillagerProfession villagerprofession = this.getVillagerData().getProfession();
+
         if (this.isBaby()) {
             brain.setSchedule(Schedule.VILLAGER_BABY);
             brain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F));
         } else {
             brain.setSchedule(Schedule.VILLAGER_DEFAULT);
-            brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerProfession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT)));
+            brain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT)));
         }
 
-        brain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerProfession, 0.5F));
-        brain.addActivityWithConditions(Activity.MEET, VillagerGoalPackages.getMeetPackage(villagerProfession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.MEETING_POINT, MemoryStatus.VALUE_PRESENT)));
-        brain.addActivity(Activity.REST, VillagerGoalPackages.getRestPackage(villagerProfession, 0.5F));
-        brain.addActivity(Activity.IDLE, VillagerGoalPackages.getIdlePackage(villagerProfession, 0.5F));
-        brain.addActivity(Activity.PANIC, VillagerGoalPackages.getPanicPackage(villagerProfession, 0.5F));
-        brain.addActivity(Activity.PRE_RAID, VillagerGoalPackages.getPreRaidPackage(villagerProfession, 0.5F));
-        brain.addActivity(Activity.RAID, VillagerGoalPackages.getRaidPackage(villagerProfession, 0.5F));
-        brain.addActivity(Activity.HIDE, VillagerGoalPackages.getHidePackage(villagerProfession, 0.5F));
+        brain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerprofession, 0.5F));
+        brain.addActivityWithConditions(Activity.MEET, VillagerGoalPackages.getMeetPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.MEETING_POINT, MemoryStatus.VALUE_PRESENT)));
+        brain.addActivity(Activity.REST, VillagerGoalPackages.getRestPackage(villagerprofession, 0.5F));
+        brain.addActivity(Activity.IDLE, VillagerGoalPackages.getIdlePackage(villagerprofession, 0.5F));
+        brain.addActivity(Activity.PANIC, VillagerGoalPackages.getPanicPackage(villagerprofession, 0.5F));
+        brain.addActivity(Activity.PRE_RAID, VillagerGoalPackages.getPreRaidPackage(villagerprofession, 0.5F));
+        brain.addActivity(Activity.RAID, VillagerGoalPackages.getRaidPackage(villagerprofession, 0.5F));
+        brain.addActivity(Activity.HIDE, VillagerGoalPackages.getHidePackage(villagerprofession, 0.5F));
         brain.setCoreActivities(ImmutableSet.of(Activity.CORE));
         brain.setDefaultActivity(Activity.IDLE);
         brain.setActiveActivityIfPossible(Activity.IDLE);
@@ -194,7 +208,7 @@
     protected void ageBoundaryReached() {
         super.ageBoundaryReached();
         if (this.level instanceof ServerLevel) {
-            this.refreshBrain((ServerLevel)this.level);
+            this.refreshBrain((ServerLevel) this.level);
         }
 
     }
@@ -207,10 +221,33 @@
         return this.assignProfessionWhenSpawned;
     }
 
+    // Spigot Start
     @Override
-    protected void customServerAiStep() {
+    public void inactiveTick() {
+        // SPIGOT-3874, SPIGOT-3894, SPIGOT-3846, SPIGOT-5286 :(
+        // Paper start
+        if (this.getUnhappyCounter() > 0) {
+            this.setUnhappyCounter(this.getUnhappyCounter() - 1);
+        }
+        if (this.isEffectiveAi()) {
+            if (level.spigotConfig.tickInactiveVillagers) {
+                this.customServerAiStep();
+            } else {
+                this.mobTick(true);
+            }
+        }
+        maybeDecayGossip();
+        // Paper end
+
+        super.inactiveTick();
+    }
+    // Spigot End
+
+    @Override
+    protected void customServerAiStep() { mobTick(false); }
+    protected void mobTick(boolean inactive) {
         this.level.getProfiler().push("villagerBrain");
-        this.getBrain().tick((ServerLevel)this.level, this);
+        if (!inactive) this.getBrain().tick((ServerLevel) this.level, this); // Paper
         this.level.getProfiler().pop();
         if (this.assignProfessionWhenSpawned) {
             this.assignProfessionWhenSpawned = false;
@@ -224,26 +261,28 @@
                     this.increaseProfessionLevelOnUpdate = false;
                 }
 
-                this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 200, 0));
+                this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.VILLAGER_TRADE); // CraftBukkit
             }
         }
 
         if (this.lastTradedPlayer != null && this.level instanceof ServerLevel) {
-            ((ServerLevel)this.level).onReputationEvent(ReputationEventType.TRADE, this.lastTradedPlayer, this);
-            this.level.broadcastEntityEvent(this, (byte)14);
+            ((ServerLevel) this.level).onReputationEvent(ReputationEventType.TRADE, this.lastTradedPlayer, this);
+            this.level.broadcastEntityEvent(this, (byte) 14);
             this.lastTradedPlayer = null;
         }
 
-        if (!this.isNoAi() && this.random.nextInt(100) == 0) {
-            Raid raid = ((ServerLevel)this.level).getRaidAt(this.blockPosition());
+        if (!inactive && !this.isNoAi() && this.random.nextInt(100) == 0) { // Paper
+            Raid raid = ((ServerLevel) this.level).getRaidAt(this.blockPosition());
+
             if (raid != null && raid.isActive() && !raid.isOver()) {
-                this.level.broadcastEntityEvent(this, (byte)42);
+                this.level.broadcastEntityEvent(this, (byte) 42);
             }
         }
 
         if (this.getVillagerData().getProfession() == VillagerProfession.NONE && this.isTrading()) {
             this.stopTrading();
         }
+        if (inactive) return; // Paper
 
         super.customServerAiStep();
     }
@@ -260,22 +299,24 @@
 
     @Override
     public InteractionResult mobInteract(Player player, InteractionHand hand) {
-        ItemStack itemStack = player.getItemInHand(hand);
-        if (!itemStack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) {
+        ItemStack itemstack = player.getItemInHand(hand);
+
+        if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) {
             if (this.isBaby()) {
                 this.setUnhappy();
                 return InteractionResult.sidedSuccess(this.level.isClientSide);
             } else {
-                boolean bl = this.getOffers().isEmpty();
+                boolean flag = this.getOffers().isEmpty();
+
                 if (hand == InteractionHand.MAIN_HAND) {
-                    if (bl && !this.level.isClientSide) {
+                    if (flag && !this.level.isClientSide) {
                         this.setUnhappy();
                     }
 
                     player.awardStat(Stats.TALKED_TO_VILLAGER);
                 }
 
-                if (bl) {
+                if (flag) {
                     return InteractionResult.sidedSuccess(this.level.isClientSide);
                 } else {
                     if (!this.level.isClientSide && !this.offers.isEmpty()) {
@@ -306,9 +347,10 @@
 
     @Override
     public void setTradingPlayer(@Nullable Player customer) {
-        boolean bl = this.getTradingPlayer() != null && customer == null;
+        boolean flag = this.getTradingPlayer() != null && customer == null;
+
         super.setTradingPlayer(customer);
-        if (bl) {
+        if (flag) {
             this.stopTrading();
         }
 
@@ -321,8 +363,12 @@
     }
 
     private void resetSpecialPrices() {
-        for(MerchantOffer merchantOffer : this.getOffers()) {
-            merchantOffer.resetSpecialPriceDiff();
+        Iterator iterator = this.getOffers().iterator();
+
+        while (iterator.hasNext()) {
+            MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+            merchantrecipe.resetSpecialPriceDiff();
         }
 
     }
@@ -339,9 +385,18 @@
 
     public void restock() {
         this.updateDemand();
+        Iterator iterator = this.getOffers().iterator();
 
-        for(MerchantOffer merchantOffer : this.getOffers()) {
-            merchantOffer.resetUses();
+        while (iterator.hasNext()) {
+            MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+            // CraftBukkit start
+            VillagerReplenishTradeEvent event = new VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantrecipe.asBukkit());
+            Bukkit.getPluginManager().callEvent(event);
+            if (!event.isCancelled()) {
+                merchantrecipe.resetUses();
+            }
+            // CraftBukkit end
         }
 
         this.lastRestockGameTime = this.level.getGameTime();
@@ -349,13 +404,19 @@
     }
 
     private boolean needsToRestock() {
-        for(MerchantOffer merchantOffer : this.getOffers()) {
-            if (merchantOffer.needsRestock()) {
-                return true;
+        Iterator iterator = this.getOffers().iterator();
+
+        MerchantOffer merchantrecipe;
+
+        do {
+            if (!iterator.hasNext()) {
+                return false;
             }
-        }
 
-        return false;
+            merchantrecipe = (MerchantOffer) iterator.next();
+        } while (!merchantrecipe.needsRestock());
+
+        return true;
     }
 
     private boolean allowedToRestock() {
@@ -363,19 +424,21 @@
     }
 
     public boolean shouldRestock() {
-        long l = this.lastRestockGameTime + 12000L;
-        long m = this.level.getGameTime();
-        boolean bl = m > l;
-        long n = this.level.getDayTime();
+        long i = this.lastRestockGameTime + 12000L;
+        long j = this.level.getGameTime();
+        boolean flag = j > i;
+        long k = this.level.getDayTime();
+
         if (this.lastRestockCheckDayTime > 0L) {
-            long o = this.lastRestockCheckDayTime / 24000L;
-            long p = n / 24000L;
-            bl |= p > o;
+            long l = this.lastRestockCheckDayTime / 24000L;
+            long i1 = k / 24000L;
+
+            flag |= i1 > l;
         }
 
-        this.lastRestockCheckDayTime = n;
-        if (bl) {
-            this.lastRestockGameTime = m;
+        this.lastRestockCheckDayTime = k;
+        if (flag) {
+            this.lastRestockGameTime = j;
             this.resetNumberOfRestocks();
         }
 
@@ -384,41 +447,66 @@
 
     private void catchUpDemand() {
         int i = 2 - this.numberOfRestocksToday;
+
         if (i > 0) {
-            for(MerchantOffer merchantOffer : this.getOffers()) {
-                merchantOffer.resetUses();
+            Iterator iterator = this.getOffers().iterator();
+
+            while (iterator.hasNext()) {
+                MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+                // CraftBukkit start
+                VillagerReplenishTradeEvent event = new VillagerReplenishTradeEvent((org.bukkit.entity.Villager) this.getBukkitEntity(), merchantrecipe.asBukkit());
+                Bukkit.getPluginManager().callEvent(event);
+                if (!event.isCancelled()) {
+                    merchantrecipe.resetUses();
+                }
+                // CraftBukkit end
             }
         }
 
-        for(int j = 0; j < i; ++j) {
+        for (int j = 0; j < i; ++j) {
             this.updateDemand();
         }
 
     }
 
     private void updateDemand() {
-        for(MerchantOffer merchantOffer : this.getOffers()) {
-            merchantOffer.updateDemand();
+        Iterator iterator = this.getOffers().iterator();
+
+        while (iterator.hasNext()) {
+            MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+            merchantrecipe.updateDemand();
         }
 
     }
 
     private void updateSpecialPrices(Player player) {
         int i = this.getPlayerReputation(player);
+
         if (i != 0) {
-            for(MerchantOffer merchantOffer : this.getOffers()) {
-                merchantOffer.addToSpecialPriceDiff(-Mth.floor((float)i * merchantOffer.getPriceMultiplier()));
+            Iterator iterator = this.getOffers().iterator();
+
+            while (iterator.hasNext()) {
+                MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+                if (merchantrecipe.ignoreDiscounts) continue; // Paper
+
+                merchantrecipe.addToSpecialPriceDiff(-Mth.floor((float) i * merchantrecipe.getPriceMultiplier()));
             }
         }
 
         if (player.hasEffect(MobEffects.HERO_OF_THE_VILLAGE)) {
-            MobEffectInstance mobEffectInstance = player.getEffect(MobEffects.HERO_OF_THE_VILLAGE);
-            int j = mobEffectInstance.getAmplifier();
+            MobEffectInstance mobeffect = player.getEffect(MobEffects.HERO_OF_THE_VILLAGE);
+            int j = mobeffect.getAmplifier();
+            Iterator iterator1 = this.getOffers().iterator();
 
-            for(MerchantOffer merchantOffer2 : this.getOffers()) {
-                double d = 0.3D + 0.0625D * (double)j;
-                int k = (int)Math.floor(d * (double)merchantOffer2.getBaseCostA().getCount());
-                merchantOffer2.addToSpecialPriceDiff(-Math.max(k, 1));
+            while (iterator1.hasNext()) {
+                MerchantOffer merchantrecipe1 = (MerchantOffer) iterator1.next();
+                if (merchantrecipe1.ignoreDiscounts) continue; // Paper
+                double d0 = 0.3D + 0.0625D * (double) j;
+                int k = (int) Math.floor(d0 * (double) merchantrecipe1.getBaseCostA().getCount());
+
+                merchantrecipe1.addToSpecialPriceDiff(-Math.max(k, 1));
             }
         }
 
@@ -427,17 +515,21 @@
     @Override
     protected void defineSynchedData() {
         super.defineSynchedData();
-        this.entityData.define(DATA_VILLAGER_DATA, new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, 1));
+        this.entityData.define(Villager.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 = Villager.LOGGER;
+
+        Objects.requireNonNull(logger);
+        dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
+            nbt.put("VillagerData", nbtbase);
         });
-        nbt.putByte("FoodLevel", (byte)this.foodLevel);
-        nbt.put("Gossips", this.gossips.store(NbtOps.INSTANCE).getValue());
+        nbt.putByte("FoodLevel", (byte) this.foodLevel);
+        nbt.put("Gossips", (Tag) this.gossips.store(NbtOps.INSTANCE).getValue());
         nbt.putInt("Xp", this.villagerXp);
         nbt.putLong("LastRestock", this.lastRestockGameTime);
         nbt.putLong("LastGossipDecay", this.lastGossipDecayTime);
@@ -452,8 +544,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 = Villager.LOGGER;
+
+            Objects.requireNonNull(logger);
+            dataresult.resultOrPartial(logger::error).ifPresent(this::setVillagerData);
         }
 
         if (nbt.contains("Offers", 10)) {
@@ -464,8 +559,9 @@
             this.foodLevel = nbt.getByte("FoodLevel");
         }
 
-        ListTag listTag = nbt.getList("Gossips", 10);
-        this.gossips.update(new Dynamic<>(NbtOps.INSTANCE, listTag));
+        ListTag nbttaglist = nbt.getList("Gossips", 10);
+
+        this.gossips.update(new Dynamic(NbtOps.INSTANCE, nbttaglist));
         if (nbt.contains("Xp", 3)) {
             this.villagerXp = nbt.getInt("Xp");
         }
@@ -474,7 +570,7 @@
         this.lastGossipDecayTime = nbt.getLong("LastGossipDecay");
         this.setCanPickUpLoot(true);
         if (this.level instanceof ServerLevel) {
-            this.refreshBrain((ServerLevel)this.level);
+            this.refreshBrain((ServerLevel) this.level);
         }
 
         this.numberOfRestocksToday = nbt.getInt("RestocksToday");
@@ -492,11 +588,7 @@
     @Nullable
     @Override
     protected SoundEvent getAmbientSound() {
-        if (this.isSleeping()) {
-            return null;
-        } else {
-            return this.isTrading() ? SoundEvents.VILLAGER_TRADE : SoundEvents.VILLAGER_AMBIENT;
-        }
+        return this.isSleeping() ? null : (this.isTrading() ? SoundEvents.VILLAGER_TRADE : SoundEvents.VILLAGER_AMBIENT);
     }
 
     @Override
@@ -510,31 +602,34 @@
     }
 
     public void playWorkSound() {
-        SoundEvent soundEvent = this.getVillagerData().getProfession().workSound();
-        if (soundEvent != null) {
-            this.playSound(soundEvent, this.getSoundVolume(), this.getVoicePitch());
+        SoundEvent soundeffect = this.getVillagerData().getProfession().workSound();
+
+        if (soundeffect != null) {
+            this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
         }
 
     }
 
     @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.offers = null;
         }
 
-        this.entityData.set(DATA_VILLAGER_DATA, villagerData);
+        this.entityData.set(Villager.DATA_VILLAGER_DATA, villagerData);
     }
 
     @Override
     public VillagerData getVillagerData() {
-        return this.entityData.get(DATA_VILLAGER_DATA);
+        return (VillagerData) this.entityData.get(Villager.DATA_VILLAGER_DATA);
     }
 
     @Override
     protected void rewardTradeXp(MerchantOffer offer) {
         int i = 3 + this.random.nextInt(4);
+
         this.villagerXp += offer.getXp();
         this.lastTradedPlayer = this.getTradingPlayer();
         if (this.shouldIncreaseLevel()) {
@@ -544,13 +639,13 @@
         }
 
         if (offer.shouldRewardExp()) {
-            this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i));
+            this.level.addFreshEntity(new ExperienceOrb(this.level, this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper
         }
 
     }
 
-    public void setChasing(boolean bl) {
-        this.chasing = bl;
+    public void setChasing(boolean flag) {
+        this.chasing = flag;
     }
 
     public boolean isChasing() {
@@ -560,9 +655,9 @@
     @Override
     public void setLastHurtByMob(@Nullable LivingEntity attacker) {
         if (attacker != null && this.level instanceof ServerLevel) {
-            ((ServerLevel)this.level).onReputationEvent(ReputationEventType.VILLAGER_HURT, attacker, this);
+            ((ServerLevel) this.level).onReputationEvent(ReputationEventType.VILLAGER_HURT, attacker, this);
             if (this.isAlive() && attacker instanceof Player) {
-                this.level.broadcastEntityEvent(this, (byte)13);
+                this.level.broadcastEntityEvent(this, (byte) 13);
             }
         }
 
@@ -571,8 +666,9 @@
 
     @Override
     public void die(DamageSource damageSource) {
-        LOGGER.info("Villager {} died, message: '{}'", this, damageSource.getLocalizedDeathMessage(this).getString());
+        if (org.spigotmc.SpigotConfig.logVillagerDeaths) Villager.LOGGER.info("Villager {} died, message: '{}'", this, damageSource.getLocalizedDeathMessage(this).getString()); // Spigot
         Entity entity = damageSource.getEntity();
+
         if (entity != null) {
             this.tellWitnessesThatIWasMurdered(entity);
         }
@@ -589,29 +685,38 @@
     }
 
     private void tellWitnessesThatIWasMurdered(Entity killer) {
-        Level optional = this.level;
-        if (optional instanceof ServerLevel serverLevel) {
-            Optional<NearestVisibleLivingEntities> optional = this.brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
+        Level world = this.level;
+
+        if (world instanceof ServerLevel) {
+            ServerLevel worldserver = (ServerLevel) world;
+            Optional optional = this.brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
+
             if (!optional.isEmpty()) {
-                optional.get().findAll(ReputationEventHandler.class::isInstance).forEach((livingEntity) -> {
-                    serverLevel.onReputationEvent(ReputationEventType.VILLAGER_KILLED, killer, (ReputationEventHandler)livingEntity);
+                NearestVisibleLivingEntities nearestvisiblelivingentities = (NearestVisibleLivingEntities) optional.get();
+
+                Objects.requireNonNull(ReputationEventHandler.class);
+                nearestvisiblelivingentities.findAll(ReputationEventHandler.class::isInstance).forEach((entityliving) -> {
+                    worldserver.onReputationEvent(ReputationEventType.VILLAGER_KILLED, killer, (ReputationEventHandler) entityliving);
                 });
             }
         }
     }
 
-    public void releasePoi(MemoryModuleType<GlobalPos> memoryModuleType) {
+    public void releasePoi(MemoryModuleType<GlobalPos> memorymoduletype) {
         if (this.level instanceof ServerLevel) {
-            MinecraftServer minecraftServer = ((ServerLevel)this.level).getServer();
-            this.brain.getMemory(memoryModuleType).ifPresent((pos) -> {
-                ServerLevel serverLevel = minecraftServer.getLevel(pos.dimension());
-                if (serverLevel != null) {
-                    PoiManager poiManager = serverLevel.getPoiManager();
-                    Optional<Holder<PoiType>> optional = poiManager.getType(pos.pos());
-                    BiPredicate<Villager, Holder<PoiType>> biPredicate = POI_MEMORIES.get(memoryModuleType);
-                    if (optional.isPresent() && biPredicate.test(this, optional.get())) {
-                        poiManager.release(pos.pos());
-                        DebugPackets.sendPoiTicketCountPacket(serverLevel, pos.pos());
+            MinecraftServer minecraftserver = ((ServerLevel) this.level).getServer();
+
+            this.brain.getMemory(memorymoduletype).ifPresent((globalpos) -> {
+                ServerLevel worldserver = minecraftserver.getLevel(globalpos.dimension());
+
+                if (worldserver != null) {
+                    PoiManager villageplace = worldserver.getPoiManager();
+                    Optional<Holder<PoiType>> optional = villageplace.getType(globalpos.pos());
+                    BiPredicate<Villager, Holder<PoiType>> bipredicate = (BiPredicate) Villager.POI_MEMORIES.get(memorymoduletype);
+
+                    if (optional.isPresent() && bipredicate.test(this, (Holder) optional.get())) {
+                        villageplace.release(globalpos.pos());
+                        DebugPackets.sendPoiTicketCountPacket(worldserver, globalpos.pos());
                     }
 
                 }
@@ -630,14 +735,16 @@
 
     private void eatUntilFull() {
         if (this.hungry() && this.countFoodPointsInInventory() != 0) {
-            for(int i = 0; i < this.getInventory().getContainerSize(); ++i) {
-                ItemStack itemStack = this.getInventory().getItem(i);
-                if (!itemStack.isEmpty()) {
-                    Integer integer = FOOD_POINTS.get(itemStack.getItem());
+            for (int i = 0; i < this.getInventory().getContainerSize(); ++i) {
+                ItemStack itemstack = this.getInventory().getItem(i);
+
+                if (!itemstack.isEmpty()) {
+                    Integer integer = (Integer) Villager.FOOD_POINTS.get(itemstack.getItem());
+
                     if (integer != null) {
-                        int j = itemStack.getCount();
+                        int j = itemstack.getCount();
 
-                        for(int k = j; k > 0; --k) {
+                        for (int k = j; k > 0; --k) {
                             this.foodLevel += integer;
                             this.getInventory().removeItem(i, 1);
                             if (!this.hungry()) {
@@ -652,7 +759,7 @@
     }
 
     public int getPlayerReputation(Player player) {
-        return this.gossips.getReputation(player.getUUID(), (gossipType) -> {
+        return this.gossips.getReputation(player.getUUID(), (reputationtype) -> {
             return true;
         });
     }
@@ -672,6 +779,7 @@
 
     private boolean shouldIncreaseLevel() {
         int i = this.getVillagerData().getLevel();
+
         return VillagerData.canLevelUp(i) && this.villagerXp >= VillagerData.getMaxXpPerLevel(i);
     }
 
@@ -682,7 +790,9 @@
 
     @Override
     protected Component getTypeName() {
-        return Component.translatable(this.getType().getDescriptionId() + "." + Registry.VILLAGER_PROFESSION.getKey(this.getVillagerData().getProfession()).getPath());
+        String s = this.getType().getDescriptionId();
+
+        return Component.translatable(s + "." + Registry.VILLAGER_PROFESSION.getKey(this.getVillagerData().getProfession()).getPath());
     }
 
     @Override
@@ -720,37 +830,53 @@
     }
 
     @Override
-    public Villager getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
-        double d = this.random.nextDouble();
-        VillagerType villagerType;
-        if (d < 0.5D) {
-            villagerType = VillagerType.byBiome(serverLevel.getBiome(this.blockPosition()));
-        } else if (d < 0.75D) {
-            villagerType = this.getVillagerData().getType();
+    public Villager getBreedOffspring(ServerLevel world, AgeableMob entity) {
+        double d0 = this.random.nextDouble();
+        VillagerType villagertype;
+
+        if (d0 < 0.5D) {
+            villagertype = VillagerType.byBiome(world.getBiome(this.blockPosition()));
+        } else if (d0 < 0.75D) {
+            villagertype = this.getVillagerData().getType();
         } else {
-            villagerType = ((Villager)ageableMob).getVillagerData().getType();
+            villagertype = ((Villager) entity).getVillagerData().getType();
         }
 
-        Villager villager = new Villager(EntityType.VILLAGER, serverLevel, villagerType);
-        villager.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(villager.blockPosition()), MobSpawnType.BREEDING, (SpawnGroupData)null, (CompoundTag)null);
-        return villager;
+        Villager entityvillager = new Villager(EntityType.VILLAGER, world, villagertype);
+
+        entityvillager.finalizeSpawn(world, world.getCurrentDifficultyAt(entityvillager.blockPosition()), MobSpawnType.BREEDING, (SpawnGroupData) null, (CompoundTag) null);
+        return entityvillager;
     }
 
     @Override
     public void thunderHit(ServerLevel world, LightningBolt lightning) {
         if (world.getDifficulty() != Difficulty.PEACEFUL) {
-            LOGGER.info("Villager {} was struck by lightning {}.", this, lightning);
-            Witch witch = EntityType.WITCH.create(world);
-            witch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
-            witch.finalizeSpawn(world, world.getCurrentDifficultyAt(witch.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData)null, (CompoundTag)null);
-            witch.setNoAi(this.isNoAi());
+            // Paper - move log down, event can cancel
+            Witch entitywitch = (Witch) EntityType.WITCH.create(world);
+
+            // Paper start
+            if (org.bukkit.craftbukkit.v1_19_R1.event.CraftEventFactory.callEntityZapEvent(this, lightning, entitywitch).isCancelled()) {
+                return;
+            }
+            // Paper end
+
+            if (org.spigotmc.SpigotConfig.logVillagerDeaths) Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightning); // Paper - move log down, event can cancel
+
+            entitywitch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+            entitywitch.finalizeSpawn(world, world.getCurrentDifficultyAt(entitywitch.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData) null, (CompoundTag) null);
+            entitywitch.setNoAi(this.isNoAi());
             if (this.hasCustomName()) {
-                witch.setCustomName(this.getCustomName());
-                witch.setCustomNameVisible(this.isCustomNameVisible());
+                entitywitch.setCustomName(this.getCustomName());
+                entitywitch.setCustomNameVisible(this.isCustomNameVisible());
             }
 
-            witch.setPersistenceRequired();
-            world.addFreshEntityWithPassengers(witch);
+            entitywitch.setPersistenceRequired();
+            // CraftBukkit start
+            if (CraftEventFactory.callEntityTransformEvent(this, entitywitch, EntityTransformEvent.TransformReason.LIGHTNING).isCancelled()) {
+                return;
+            }
+            world.addFreshEntityWithPassengers(entitywitch, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING);
+            // CraftBukkit end
             this.releaseAllPois();
             this.discard();
         } else {
@@ -767,7 +893,8 @@
     @Override
     public boolean wantsToPickUp(ItemStack stack) {
         Item item = stack.getItem();
-        return (WANTED_ITEMS.contains(item) || this.getVillagerData().getProfession().requestedItems().contains(item)) && this.getInventory().canAddItem(stack);
+
+        return (Villager.WANTED_ITEMS.contains(item) || this.getVillagerData().getProfession().requestedItems().contains(item)) && this.getInventory().canAddItem(stack);
     }
 
     public boolean hasExcessFood() {
@@ -779,9 +906,10 @@
     }
 
     private int countFoodPointsInInventory() {
-        SimpleContainer simpleContainer = this.getInventory();
-        return FOOD_POINTS.entrySet().stream().mapToInt((item) -> {
-            return simpleContainer.countItem(item.getKey()) * item.getValue();
+        SimpleContainer inventorysubcontainer = this.getInventory();
+
+        return Villager.FOOD_POINTS.entrySet().stream().mapToInt((entry) -> {
+            return inventorysubcontainer.countItem((Item) entry.getKey()) * (Integer) entry.getValue();
         }).sum();
     }
 
@@ -791,15 +919,26 @@
 
     @Override
     protected void updateTrades() {
-        VillagerData villagerData = this.getVillagerData();
-        Int2ObjectMap<VillagerTrades.ItemListing[]> int2ObjectMap = VillagerTrades.TRADES.get(villagerData.getProfession());
-        if (int2ObjectMap != null && !int2ObjectMap.isEmpty()) {
-            VillagerTrades.ItemListing[] itemListings = int2ObjectMap.get(villagerData.getLevel());
-            if (itemListings != null) {
-                MerchantOffers merchantOffers = this.getOffers();
-                this.addOffersFromItemListings(merchantOffers, itemListings, 2);
+        // Paper start
+        updateTrades(TRADES_PER_LEVEL);
+    }
+
+    public boolean updateTrades(int amount) {
+        // Paper end
+        VillagerData villagerdata = this.getVillagerData();
+        Int2ObjectMap<VillagerTrades.ItemListing[]> int2objectmap = (Int2ObjectMap) VillagerTrades.TRADES.get(villagerdata.getProfession());
+
+        if (int2objectmap != null && !int2objectmap.isEmpty()) {
+            VillagerTrades.ItemListing[] avillagertrades_imerchantrecipeoption = (VillagerTrades.ItemListing[]) int2objectmap.get(villagerdata.getLevel());
+
+            if (avillagertrades_imerchantrecipeoption != null) {
+                MerchantOffers merchantrecipelist = this.getOffers();
+
+                this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, amount); // Paper
+                return true; // Paper
             }
         }
+        return false; // Paper
     }
 
     public void gossip(ServerLevel world, Villager villager, long time) {
@@ -812,24 +951,26 @@
     }
 
     private void maybeDecayGossip() {
-        long l = this.level.getGameTime();
+        long i = this.level.getGameTime();
+
         if (this.lastGossipDecayTime == 0L) {
-            this.lastGossipDecayTime = l;
-        } else if (l >= this.lastGossipDecayTime + 24000L) {
+            this.lastGossipDecayTime = i;
+        } else if (i >= this.lastGossipDecayTime + 24000L) {
             this.gossips.decay();
-            this.lastGossipDecayTime = l;
+            this.lastGossipDecayTime = i;
         }
     }
 
     public void spawnGolemIfNeeded(ServerLevel world, long time, int requiredCount) {
         if (this.wantsToSpawnGolem(time)) {
-            AABB aABB = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
-            List<Villager> list = world.getEntitiesOfClass(Villager.class, aABB);
-            List<Villager> list2 = list.stream().filter((villager) -> {
-                return villager.wantsToSpawnGolem(time);
+            AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
+            List<Villager> list = world.getEntitiesOfClass(Villager.class, axisalignedbb);
+            List<Villager> list1 = (List) list.stream().filter((entityvillager) -> {
+                return entityvillager.wantsToSpawnGolem(time);
             }).limit(5L).collect(Collectors.toList());
-            if (list2.size() >= requiredCount) {
-                if (SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM).isPresent()) {
+
+            if (list1.size() >= requiredCount) {
+                if (SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE, () -> {GolemSensor.golemDetected(this);}).isPresent()) { // CraftBukkit // Paper - Set Golem Last Seen to stop it from spawning another one
                     list.forEach(GolemSensor::golemDetected);
                 }
             }
@@ -837,16 +978,21 @@
     }
 
     public boolean wantsToSpawnGolem(long time) {
-        if (!this.golemSpawnConditionsMet(this.level.getGameTime())) {
-            return false;
-        } else {
-            return !this.brain.hasMemoryValue(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
-        }
+        return !this.golemSpawnConditionsMet(this.level.getGameTime()) ? false : !this.brain.hasMemoryValue(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
     }
 
     @Override
     public void onReputationEventFrom(ReputationEventType interaction, Entity entity) {
         if (interaction == ReputationEventType.ZOMBIE_VILLAGER_CURED) {
+            // Paper start - fix MC-181190
+            if (level.paperConfig().fixes.fixCuringZombieVillagerDiscountExploit) {
+                final GossipContainer.EntityGossips playerReputation = this.getGossips().getReputations().get(entity.getUUID());
+                if (playerReputation != null) {
+                    playerReputation.remove(GossipType.MAJOR_POSITIVE);
+                    playerReputation.remove(GossipType.MINOR_POSITIVE);
+                }
+            }
+            // Paper end
             this.gossips.add(entity.getUUID(), GossipType.MAJOR_POSITIVE, 20);
             this.gossips.add(entity.getUUID(), GossipType.MINOR_POSITIVE, 25);
         } else if (interaction == ReputationEventType.TRADE) {
@@ -878,7 +1024,7 @@
     }
 
     public void setGossips(Tag nbt) {
-        this.gossips.update(new Dynamic<>(NbtOps.INSTANCE, nbt));
+        this.gossips.update(new Dynamic(NbtOps.INSTANCE, nbt));
     }
 
     @Override
@@ -890,7 +1036,7 @@
     @Override
     public void startSleeping(BlockPos pos) {
         super.startSleeping(pos);
-        this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level.getGameTime());
+        this.brain.setMemory(MemoryModuleType.LAST_SLEPT, this.level.getGameTime()); // CraftBukkit - decompile error
         this.brain.eraseMemory(MemoryModuleType.WALK_TARGET);
         this.brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
     }
@@ -898,15 +1044,12 @@
     @Override
     public void stopSleeping() {
         super.stopSleeping();
-        this.brain.setMemory(MemoryModuleType.LAST_WOKEN, this.level.getGameTime());
+        this.brain.setMemory(MemoryModuleType.LAST_WOKEN, this.level.getGameTime()); // CraftBukkit - decompile error
     }
 
     private boolean golemSpawnConditionsMet(long worldTime) {
         Optional<Long> optional = this.brain.getMemory(MemoryModuleType.LAST_SLEPT);
-        if (optional.isPresent()) {
-            return worldTime - optional.get() < 24000L;
-        } else {
-            return false;
-        }
+
+        return optional.isPresent() ? worldTime - (Long) optional.get() < 24000L : false;
     }
 }
