aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch')
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch1148
1 files changed, 1148 insertions, 0 deletions
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch
new file mode 100644
index 0000000000..f8f81ca094
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/entity/npc/Villager.java.patch
@@ -0,0 +1,1148 @@
+--- a/net/minecraft/world/entity/npc/Villager.java
++++ b/net/minecraft/world/entity/npc/Villager.java
+@@ -9,11 +9,12 @@
+ 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.Map.Entry;
+ import java.util.function.BiPredicate;
+ import java.util.stream.Collectors;
+ import javax.annotation.Nullable;
+@@ -41,7 +42,7 @@
+ import net.minecraft.util.SpawnUtil;
+ import net.minecraft.world.Difficulty;
+ import net.minecraft.world.DifficultyInstance;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.SimpleContainer;
+ import net.minecraft.world.damagesource.DamageSource;
+@@ -50,13 +51,13 @@
+ import net.minecraft.world.entity.AgeableMob;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntityType;
++import net.minecraft.world.entity.EnumMobSpawn;
+ import net.minecraft.world.entity.ExperienceOrb;
++import net.minecraft.world.entity.GroupDataEntity;
+ import net.minecraft.world.entity.LightningBolt;
+ import net.minecraft.world.entity.LivingEntity;
+ import net.minecraft.world.entity.Mob;
+-import net.minecraft.world.entity.MobSpawnType;
+ import net.minecraft.world.entity.ReputationEventHandler;
+-import net.minecraft.world.entity.SpawnGroupData;
+ import net.minecraft.world.entity.ai.Brain;
+ import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
+ import net.minecraft.world.entity.ai.attributes.Attributes;
+@@ -91,23 +92,21 @@
+ import net.minecraft.world.phys.AABB;
+ import org.slf4j.Logger;
+
++// CraftBukkit start
++import org.bukkit.Bukkit;
++import org.bukkit.craftbukkit.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,
+- Items.TORCHFLOWER_SEEDS,
+- Items.PITCHER_POD
+- );
++ 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, Items.TORCHFLOWER_SEEDS, Items.PITCHER_POD});
+ private static final int MAX_GOSSIP_TOPICS = 10;
+ private static final int GOSSIP_COOLDOWN = 1200;
+ private static final int GOSSIP_DECAY_INTERVAL = 24000;
+@@ -123,7 +122,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;
+@@ -131,59 +130,17 @@
+ private 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.ITEM_PICKUP_COOLDOWN_TICKS,
+- 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<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) -> holder.is(PoiTypes.HOME),
+- MemoryModuleType.JOB_SITE,
+- (villager, holder) -> villager.getVillagerData().getProfession().heldJobSite().test(holder),
+- MemoryModuleType.POTENTIAL_JOB_SITE,
+- (villager, holder) -> VillagerProfession.ALL_ACQUIRABLE_JOBS.test(holder),
+- MemoryModuleType.MEETING_POINT,
+- (villager, holder) -> holder.is(PoiTypes.MEETING)
+- );
++ 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.ITEM_PICKUP_COOLDOWN_TICKS, new MemoryModuleType[]{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<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, (entityvillager, holder) -> {
++ return holder.is(PoiTypes.HOME);
++ }, 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, (entityvillager, holder) -> {
++ return holder.is(PoiTypes.MEETING);
++ });
+
+ public Villager(EntityType<? extends Villager> entityType, Level level) {
+ this(entityType, level, VillagerType.PLAINS);
+@@ -191,7 +148,8 @@
+
+ public Villager(EntityType<? extends Villager> entityType, Level level, VillagerType villagerType) {
+ super(entityType, level);
+- ((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(villagerType).setProfession(VillagerProfession.NONE));
+@@ -199,54 +157,49 @@
+
+ @Override
+ public Brain<Villager> getBrain() {
+- return (Brain<Villager>)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 serverLevel) {
+- Brain<Villager> brain = this.getBrain();
+- brain.stopAll(serverLevel, this);
+- this.brain = brain.copyWithoutBehaviors();
++ Brain<Villager> behaviorcontroller = this.getBrain();
++
++ behaviorcontroller.stopAll(serverLevel, this);
++ this.brain = behaviorcontroller.copyWithoutBehaviors();
+ this.registerBrainGoals(this.getBrain());
+ }
+
+ private void registerBrainGoals(Brain<Villager> villagerBrain) {
+- VillagerProfession profession = this.getVillagerData().getProfession();
++ VillagerProfession villagerprofession = this.getVillagerData().getProfession();
++
+ if (this.isBaby()) {
+ villagerBrain.setSchedule(Schedule.VILLAGER_BABY);
+ villagerBrain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F));
+ } else {
+ villagerBrain.setSchedule(Schedule.VILLAGER_DEFAULT);
+- villagerBrain.addActivityWithConditions(
+- Activity.WORK,
+- VillagerGoalPackages.getWorkPackage(profession, 0.5F),
+- ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT))
+- );
++ villagerBrain.addActivityWithConditions(Activity.WORK, VillagerGoalPackages.getWorkPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.JOB_SITE, MemoryStatus.VALUE_PRESENT)));
+ }
+
+- villagerBrain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(profession, 0.5F));
+- villagerBrain.addActivityWithConditions(
+- Activity.MEET,
+- VillagerGoalPackages.getMeetPackage(profession, 0.5F),
+- ImmutableSet.of(Pair.of(MemoryModuleType.MEETING_POINT, MemoryStatus.VALUE_PRESENT))
+- );
+- villagerBrain.addActivity(Activity.REST, VillagerGoalPackages.getRestPackage(profession, 0.5F));
+- villagerBrain.addActivity(Activity.IDLE, VillagerGoalPackages.getIdlePackage(profession, 0.5F));
+- villagerBrain.addActivity(Activity.PANIC, VillagerGoalPackages.getPanicPackage(profession, 0.5F));
+- villagerBrain.addActivity(Activity.PRE_RAID, VillagerGoalPackages.getPreRaidPackage(profession, 0.5F));
+- villagerBrain.addActivity(Activity.RAID, VillagerGoalPackages.getRaidPackage(profession, 0.5F));
+- villagerBrain.addActivity(Activity.HIDE, VillagerGoalPackages.getHidePackage(profession, 0.5F));
++ villagerBrain.addActivity(Activity.CORE, VillagerGoalPackages.getCorePackage(villagerprofession, 0.5F));
++ villagerBrain.addActivityWithConditions(Activity.MEET, VillagerGoalPackages.getMeetPackage(villagerprofession, 0.5F), ImmutableSet.of(Pair.of(MemoryModuleType.MEETING_POINT, MemoryStatus.VALUE_PRESENT)));
++ villagerBrain.addActivity(Activity.REST, VillagerGoalPackages.getRestPackage(villagerprofession, 0.5F));
++ villagerBrain.addActivity(Activity.IDLE, VillagerGoalPackages.getIdlePackage(villagerprofession, 0.5F));
++ villagerBrain.addActivity(Activity.PANIC, VillagerGoalPackages.getPanicPackage(villagerprofession, 0.5F));
++ villagerBrain.addActivity(Activity.PRE_RAID, VillagerGoalPackages.getPreRaidPackage(villagerprofession, 0.5F));
++ villagerBrain.addActivity(Activity.RAID, VillagerGoalPackages.getRaidPackage(villagerprofession, 0.5F));
++ villagerBrain.addActivity(Activity.HIDE, VillagerGoalPackages.getHidePackage(villagerprofession, 0.5F));
+ villagerBrain.setCoreActivities(ImmutableSet.of(Activity.CORE));
+ villagerBrain.setDefaultActivity(Activity.IDLE);
+ villagerBrain.setActiveActivityIfPossible(Activity.IDLE);
+@@ -257,12 +210,13 @@
+ protected void ageBoundaryReached() {
+ super.ageBoundaryReached();
+ if (this.level() instanceof ServerLevel) {
+- this.refreshBrain((ServerLevel)this.level());
++ this.refreshBrain((ServerLevel) this.level());
+ }
++
+ }
+
+ public static AttributeSupplier.Builder createAttributes() {
+- return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.5).add(Attributes.FOLLOW_RANGE, 48.0);
++ return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.5D).add(Attributes.FOLLOW_RANGE, 48.0D);
+ }
+
+ public boolean assignProfessionWhenSpawned() {
+@@ -272,34 +226,35 @@
+ @Override
+ protected void customServerAiStep() {
+ this.level().getProfiler().push("villagerBrain");
+- this.getBrain().tick((ServerLevel)this.level(), this);
++ this.getBrain().tick((ServerLevel) this.level(), this);
+ this.level().getProfiler().pop();
+ if (this.assignProfessionWhenSpawned) {
+ this.assignProfessionWhenSpawned = false;
+ }
+
+ if (!this.isTrading() && this.updateMerchantTimer > 0) {
+- this.updateMerchantTimer--;
++ --this.updateMerchantTimer;
+ if (this.updateMerchantTimer <= 0) {
+ if (this.increaseProfessionLevelOnUpdate) {
+ this.increaseMerchantCareer();
+ 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 raidAt = ((ServerLevel)this.level()).getRaidAt(this.blockPosition());
+- if (raidAt != null && raidAt.isActive() && !raidAt.isOver()) {
+- this.level().broadcastEntityEvent(this, (byte)42);
++ Raid raid = ((ServerLevel) this.level()).getRaidAt(this.blockPosition());
++
++ if (raid != null && raid.isActive() && !raid.isOver()) {
++ this.level().broadcastEntityEvent(this, (byte) 42);
+ }
+ }
+
+@@ -321,40 +276,45 @@
+ }
+
+ @Override
+- public InteractionResult mobInteract(Player player, InteractionHand hand) {
+- ItemStack itemInHand = player.getItemInHand(hand);
+- if (itemInHand.is(Items.VILLAGER_SPAWN_EGG) || !this.isAlive() || this.isTrading() || this.isSleeping()) {
+- return super.mobInteract(player, hand);
+- } else if (this.isBaby()) {
+- this.setUnhappy();
+- return InteractionResult.sidedSuccess(this.level().isClientSide);
+- } else {
+- boolean isEmpty = this.getOffers().isEmpty();
+- if (hand == InteractionHand.MAIN_HAND) {
+- if (isEmpty && !this.level().isClientSide) {
+- this.setUnhappy();
+- }
++ public InteractionResult mobInteract(Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+- player.awardStat(Stats.TALKED_TO_VILLAGER);
+- }
+-
+- if (isEmpty) {
++ 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 {
+- if (!this.level().isClientSide && !this.offers.isEmpty()) {
+- this.startTrading(player);
++ boolean flag = this.getOffers().isEmpty();
++
++ if (hand == EnumHand.MAIN_HAND) {
++ if (flag && !this.level().isClientSide) {
++ this.setUnhappy();
++ }
++
++ player.awardStat(Stats.TALKED_TO_VILLAGER);
+ }
+
+- return InteractionResult.sidedSuccess(this.level().isClientSide);
++ if (flag) {
++ return InteractionResult.sidedSuccess(this.level().isClientSide);
++ } else {
++ if (!this.level().isClientSide && !this.offers.isEmpty()) {
++ this.startTrading(player);
++ }
++
++ return InteractionResult.sidedSuccess(this.level().isClientSide);
++ }
+ }
++ } else {
++ return super.mobInteract(player, hand);
+ }
+ }
+
+- private void setUnhappy() {
++ public void setUnhappy() {
+ this.setUnhappyCounter(40);
+ if (!this.level().isClientSide()) {
+ this.playSound(SoundEvents.VILLAGER_NO, this.getSoundVolume(), this.getVoicePitch());
+ }
++
+ }
+
+ private void startTrading(Player player) {
+@@ -366,10 +326,12 @@
+ @Override
+ public void setTradingPlayer(@Nullable Player player) {
+ boolean flag = this.getTradingPlayer() != null && player == null;
++
+ super.setTradingPlayer(player);
+ if (flag) {
+ this.stopTrading();
+ }
++
+ }
+
+ @Override
+@@ -379,9 +341,14 @@
+ }
+
+ 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();
+ }
++
+ }
+
+ @Override
+@@ -396,39 +363,49 @@
+
+ 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.resendOffersToTradingPlayer();
+ this.lastRestockGameTime = this.level().getGameTime();
+- this.numberOfRestocksToday++;
++ ++this.numberOfRestocksToday;
+ }
+
+ private void resendOffersToTradingPlayer() {
+- MerchantOffers offers = this.getOffers();
+- Player tradingPlayer = this.getTradingPlayer();
+- if (tradingPlayer != null && !offers.isEmpty()) {
+- tradingPlayer.sendMerchantOffers(
+- tradingPlayer.containerMenu.containerId,
+- offers,
+- this.getVillagerData().getLevel(),
+- this.getVillagerXp(),
+- this.showProgressBar(),
+- this.canRestock()
+- );
++ MerchantOffers merchantrecipelist = this.getOffers();
++ Player entityhuman = this.getTradingPlayer();
++
++ if (entityhuman != null && !merchantrecipelist.isEmpty()) {
++ entityhuman.sendMerchantOffers(entityhuman.containerMenu.containerId, merchantrecipelist, this.getVillagerData().getLevel(), this.getVillagerXp(), this.showProgressBar(), this.canRestock());
+ }
++
+ }
+
+ 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() {
+@@ -436,19 +413,21 @@
+ }
+
+ public boolean shouldRestock() {
+- long l = this.lastRestockGameTime + 12000L;
+- long gameTime = this.level().getGameTime();
+- boolean flag = gameTime > l;
+- long dayTime = 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 l1 = this.lastRestockCheckDayTime / 24000L;
+- long l2 = dayTime / 24000L;
+- flag |= l2 > l1;
++ long l = this.lastRestockCheckDayTime / 24000L;
++ long i1 = k / 24000L;
++
++ flag |= i1 > l;
+ }
+
+- this.lastRestockCheckDayTime = dayTime;
++ this.lastRestockCheckDayTime = k;
+ if (flag) {
+- this.lastRestockGameTime = gameTime;
++ this.lastRestockGameTime = j;
+ this.resetNumberOfRestocks();
+ }
+
+@@ -457,13 +436,24 @@
+
+ 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 i1 = 0; i1 < i; i1++) {
++ for (int j = 0; j < i; ++j) {
+ this.updateDemand();
+ }
+
+@@ -471,46 +461,63 @@
+ }
+
+ 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 playerReputation = this.getPlayerReputation(player);
+- if (playerReputation != 0) {
+- for (MerchantOffer merchantOffer : this.getOffers()) {
+- merchantOffer.addToSpecialPriceDiff(-Mth.floor((float)playerReputation * merchantOffer.getPriceMultiplier()));
++ int i = this.getPlayerReputation(player);
++
++ if (i != 0) {
++ Iterator iterator = this.getOffers().iterator();
++
++ while (iterator.hasNext()) {
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
++
++ merchantrecipe.addToSpecialPriceDiff(-Mth.floor((float) i * merchantrecipe.getPriceMultiplier()));
+ }
+ }
+
+ if (player.hasEffect(MobEffects.HERO_OF_THE_VILLAGE)) {
+- MobEffectInstance effect = player.getEffect(MobEffects.HERO_OF_THE_VILLAGE);
+- int amplifier = effect.getAmplifier();
++ MobEffectInstance mobeffect = player.getEffect(MobEffects.HERO_OF_THE_VILLAGE);
++ int j = mobeffect.getAmplifier();
++ Iterator iterator1 = this.getOffers().iterator();
+
+- for (MerchantOffer merchantOffer1 : this.getOffers()) {
+- double d = 0.3 + 0.0625 * (double)amplifier;
+- int i = (int)Math.floor(d * (double)merchantOffer1.getBaseCostA().getCount());
+- merchantOffer1.addToSpecialPriceDiff(-Math.max(i, 1));
++ while (iterator1.hasNext()) {
++ MerchantOffer merchantrecipe1 = (MerchantOffer) iterator1.next();
++ double d0 = 0.3D + 0.0625D * (double) j;
++ int k = (int) Math.floor(d0 * (double) merchantrecipe1.getBaseCostA().getCount());
++
++ merchantrecipe1.addToSpecialPriceDiff(-Math.max(k, 1));
+ }
+ }
++
+ }
+
+ @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 compound) {
+ super.addAdditionalSaveData(compound);
+- VillagerData.CODEC
+- .encodeStart(NbtOps.INSTANCE, this.getVillagerData())
+- .resultOrPartial(LOGGER::error)
+- .ifPresent(tag -> compound.put("VillagerData", tag));
+- compound.putByte("FoodLevel", (byte)this.foodLevel);
+- compound.put("Gossips", this.gossips.store(NbtOps.INSTANCE));
++ 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) -> {
++ compound.put("VillagerData", nbtbase);
++ });
++ compound.putByte("FoodLevel", (byte) this.foodLevel);
++ compound.put("Gossips", (Tag) this.gossips.store(NbtOps.INSTANCE));
+ compound.putInt("Xp", this.villagerXp);
+ compound.putLong("LastRestock", this.lastRestockGameTime);
+ compound.putLong("LastGossipDecay", this.lastGossipDecayTime);
+@@ -518,14 +525,18 @@
+ if (this.assignProfessionWhenSpawned) {
+ compound.putBoolean("AssignProfessionWhenSpawned", true);
+ }
++
+ }
+
+ @Override
+ public void readAdditionalSaveData(CompoundTag compound) {
+ super.readAdditionalSaveData(compound);
+ if (compound.contains("VillagerData", 10)) {
+- DataResult<VillagerData> dataResult = VillagerData.CODEC.parse(new Dynamic<>(NbtOps.INSTANCE, compound.get("VillagerData")));
+- dataResult.resultOrPartial(LOGGER::error).ifPresent(this::setVillagerData);
++ DataResult<VillagerData> dataresult = VillagerData.CODEC.parse(new Dynamic(NbtOps.INSTANCE, compound.get("VillagerData")));
++ Logger logger = Villager.LOGGER;
++
++ Objects.requireNonNull(logger);
++ dataresult.resultOrPartial(logger::error).ifPresent(this::setVillagerData);
+ }
+
+ if (compound.contains("Offers", 10)) {
+@@ -536,8 +547,9 @@
+ this.foodLevel = compound.getByte("FoodLevel");
+ }
+
+- ListTag list = compound.getList("Gossips", 10);
+- this.gossips.update(new Dynamic<>(NbtOps.INSTANCE, list));
++ ListTag nbttaglist = compound.getList("Gossips", 10);
++
++ this.gossips.update(new Dynamic(NbtOps.INSTANCE, nbttaglist));
+ if (compound.contains("Xp", 3)) {
+ this.villagerXp = compound.getInt("Xp");
+ }
+@@ -546,13 +558,14 @@
+ this.lastGossipDecayTime = compound.getLong("LastGossipDecay");
+ this.setCanPickUpLoot(true);
+ if (this.level() instanceof ServerLevel) {
+- this.refreshBrain((ServerLevel)this.level());
++ this.refreshBrain((ServerLevel) this.level());
+ }
+
+ this.numberOfRestocksToday = compound.getInt("RestocksToday");
+ if (compound.contains("AssignProfessionWhenSpawned")) {
+ this.assignProfessionWhenSpawned = compound.getBoolean("AssignProfessionWhenSpawned");
+ }
++
+ }
+
+ @Override
+@@ -563,11 +576,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
+@@ -581,31 +590,35 @@
+ }
+
+ 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 data) {
+- VillagerData villagerData = this.getVillagerData();
+- if (villagerData.getProfession() != data.getProfession()) {
++ VillagerData villagerdata1 = this.getVillagerData();
++
++ if (villagerdata1.getProfession() != data.getProfession()) {
+ this.offers = null;
+ }
+
+- this.entityData.set(DATA_VILLAGER_DATA, data);
++ this.entityData.set(Villager.DATA_VILLAGER_DATA, data);
+ }
+
+ @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 = this.villagerXp + offer.getXp();
++
++ this.villagerXp += offer.getXp();
+ this.lastTradedPlayer = this.getTradingPlayer();
+ if (this.shouldIncreaseLevel()) {
+ this.updateMerchantTimer = 40;
+@@ -614,8 +627,9 @@
+ }
+
+ if (offer.shouldRewardExp()) {
+- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5, this.getZ(), i));
++ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i));
+ }
++
+ }
+
+ public void setChasing(boolean chasing) {
+@@ -629,9 +643,9 @@
+ @Override
+ public void setLastHurtByMob(@Nullable LivingEntity livingBase) {
+ if (livingBase != null && this.level() instanceof ServerLevel) {
+- ((ServerLevel)this.level()).onReputationEvent(ReputationEventType.VILLAGER_HURT, livingBase, this);
++ ((ServerLevel) this.level()).onReputationEvent(ReputationEventType.VILLAGER_HURT, livingBase, this);
+ if (this.isAlive() && livingBase instanceof Player) {
+- this.level().broadcastEntityEvent(this, (byte)13);
++ this.level().broadcastEntityEvent(this, (byte) 13);
+ }
+ }
+
+@@ -640,8 +654,9 @@
+
+ @Override
+ public void die(DamageSource cause) {
+- LOGGER.info("Villager {} died, message: '{}'", this, cause.getLocalizedDeathMessage(this).getString());
++ Villager.LOGGER.info("Villager {} died, message: '{}'", this, cause.getLocalizedDeathMessage(this).getString());
+ Entity entity = cause.getEntity();
++
+ if (entity != null) {
+ this.tellWitnessesThatIWasMurdered(entity);
+ }
+@@ -650,7 +665,7 @@
+ super.die(cause);
+ }
+
+- private void releaseAllPois() {
++ public void releaseAllPois() {
+ this.releasePoi(MemoryModuleType.HOME);
+ this.releasePoi(MemoryModuleType.JOB_SITE);
+ this.releasePoi(MemoryModuleType.POTENTIAL_JOB_SITE);
+@@ -658,29 +673,40 @@
+ }
+
+ private void tellWitnessesThatIWasMurdered(Entity murderer) {
+- if (this.level() instanceof ServerLevel serverLevel) {
+- Optional<NearestVisibleLivingEntities> memory = this.brain.getMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES);
+- if (!memory.isEmpty()) {
+- memory.get()
+- .findAll(ReputationEventHandler.class::isInstance)
+- .forEach(host -> serverLevel.onReputationEvent(ReputationEventType.VILLAGER_KILLED, murderer, (ReputationEventHandler)host));
++ 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()) {
++ NearestVisibleLivingEntities nearestvisiblelivingentities = (NearestVisibleLivingEntities) optional.get();
++
++ Objects.requireNonNull(ReputationEventHandler.class);
++ nearestvisiblelivingentities.findAll(ReputationEventHandler.class::isInstance).forEach((entityliving) -> {
++ worldserver.onReputationEvent(ReputationEventType.VILLAGER_KILLED, murderer, (ReputationEventHandler) entityliving);
++ });
+ }
+ }
+ }
+
+ public void releasePoi(MemoryModuleType<GlobalPos> moduleType) {
+ if (this.level() instanceof ServerLevel) {
+- MinecraftServer server = ((ServerLevel)this.level()).getServer();
+- this.brain.getMemory(moduleType).ifPresent(globalPos -> {
+- ServerLevel level = server.getLevel(globalPos.dimension());
+- if (level != null) {
+- PoiManager poiManager = level.getPoiManager();
+- Optional<Holder<PoiType>> type = poiManager.getType(globalPos.pos());
+- BiPredicate<Villager, Holder<PoiType>> biPredicate = POI_MEMORIES.get(moduleType);
+- if (type.isPresent() && biPredicate.test(this, type.get())) {
+- poiManager.release(globalPos.pos());
+- DebugPackets.sendPoiTicketCountPacket(level, globalPos.pos());
++ MinecraftServer minecraftserver = ((ServerLevel) this.level()).getServer();
++
++ this.brain.getMemory(moduleType).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(moduleType);
++
++ if (optional.isPresent() && bipredicate.test(this, (Holder) optional.get())) {
++ villageplace.release(globalpos.pos());
++ DebugPackets.sendPoiTicketCountPacket(worldserver, globalpos.pos());
+ }
++
+ }
+ });
+ }
+@@ -697,15 +723,17 @@
+
+ private void eatUntilFull() {
+ if (this.hungry() && this.countFoodPointsInInventory() != 0) {
+- for (int i = 0; i < this.getInventory().getContainerSize(); i++) {
+- ItemStack item = this.getInventory().getItem(i);
+- if (!item.isEmpty()) {
+- Integer integer = FOOD_POINTS.get(item.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 count = item.getCount();
++ int j = itemstack.getCount();
+
+- for (int i1 = count; i1 > 0; i1--) {
+- this.foodLevel = this.foodLevel + integer;
++ for (int k = j; k > 0; --k) {
++ this.foodLevel += integer;
+ this.getInventory().removeItem(i, 1);
+ if (!this.hungry()) {
+ return;
+@@ -714,11 +742,14 @@
+ }
+ }
+ }
++
+ }
+ }
+
+ public int getPlayerReputation(Player player) {
+- return this.gossips.getReputation(player.getUUID(), gossipType -> true);
++ return this.gossips.getReputation(player.getUUID(), (reputationtype) -> {
++ return true;
++ });
+ }
+
+ private void digestFood(int qty) {
+@@ -735,20 +766,21 @@
+ }
+
+ private boolean shouldIncreaseLevel() {
+- int level = this.getVillagerData().getLevel();
+- return VillagerData.canLevelUp(level) && this.villagerXp >= VillagerData.getMaxXpPerLevel(level);
++ int i = this.getVillagerData().getLevel();
++
++ return VillagerData.canLevelUp(i) && this.villagerXp >= VillagerData.getMaxXpPerLevel(i);
+ }
+
+- private void increaseMerchantCareer() {
++ public void increaseMerchantCareer() {
+ this.setVillagerData(this.getVillagerData().setLevel(this.getVillagerData().getLevel() + 1));
+ this.updateTrades();
+ }
+
+ @Override
+ protected Component getTypeName() {
+- return Component.translatable(
+- this.getType().getDescriptionId() + "." + BuiltInRegistries.VILLAGER_PROFESSION.getKey(this.getVillagerData().getProfession()).getPath()
+- );
++ String s = this.getType().getDescriptionId();
++
++ return Component.translatable(s + "." + BuiltInRegistries.VILLAGER_PROFESSION.getKey(this.getVillagerData().getProfession()).getPath());
+ }
+
+ @Override
+@@ -764,22 +796,21 @@
+ } else {
+ super.handleEntityEvent(id);
+ }
++
+ }
+
+ @Nullable
+ @Override
+- public SpawnGroupData finalizeSpawn(
+- ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType reason, @Nullable SpawnGroupData spawnData, @Nullable CompoundTag dataTag
+- ) {
+- if (reason == MobSpawnType.BREEDING) {
++ public GroupDataEntity finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EnumMobSpawn reason, @Nullable GroupDataEntity spawnData, @Nullable CompoundTag dataTag) {
++ if (reason == EnumMobSpawn.BREEDING) {
+ this.setVillagerData(this.getVillagerData().setProfession(VillagerProfession.NONE));
+ }
+
+- if (reason == MobSpawnType.COMMAND || reason == MobSpawnType.SPAWN_EGG || MobSpawnType.isSpawner(reason) || reason == MobSpawnType.DISPENSER) {
++ if (reason == EnumMobSpawn.COMMAND || reason == EnumMobSpawn.SPAWN_EGG || EnumMobSpawn.isSpawner(reason) || reason == EnumMobSpawn.DISPENSER) {
+ this.setVillagerData(this.getVillagerData().setType(VillagerType.byBiome(level.getBiome(this.blockPosition()))));
+ }
+
+- if (reason == MobSpawnType.STRUCTURE) {
++ if (reason == EnumMobSpawn.STRUCTURE) {
+ this.assignProfessionWhenSpawned = true;
+ }
+
+@@ -789,37 +820,45 @@
+ @Nullable
+ @Override
+ public Villager getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
+- double randomDouble = this.random.nextDouble();
+- VillagerType villagerType;
+- if (randomDouble < 0.5) {
+- villagerType = VillagerType.byBiome(level.getBiome(this.blockPosition()));
+- } else if (randomDouble < 0.75) {
+- villagerType = this.getVillagerData().getType();
++ double d0 = this.random.nextDouble();
++ VillagerType villagertype;
++
++ if (d0 < 0.5D) {
++ villagertype = VillagerType.byBiome(level.getBiome(this.blockPosition()));
++ } else if (d0 < 0.75D) {
++ villagertype = this.getVillagerData().getType();
+ } else {
+- villagerType = ((Villager)otherParent).getVillagerData().getType();
++ villagertype = ((Villager) otherParent).getVillagerData().getType();
+ }
+
+- Villager villager = new Villager(EntityType.VILLAGER, level, villagerType);
+- villager.finalizeSpawn(level, level.getCurrentDifficultyAt(villager.blockPosition()), MobSpawnType.BREEDING, null, null);
+- return villager;
++ Villager entityvillager = new Villager(EntityType.VILLAGER, level, villagertype);
++
++ entityvillager.finalizeSpawn(level, level.getCurrentDifficultyAt(entityvillager.blockPosition()), EnumMobSpawn.BREEDING, (GroupDataEntity) null, (CompoundTag) null);
++ return entityvillager;
+ }
+
+ @Override
+ public void thunderHit(ServerLevel level, LightningBolt lightning) {
+ if (level.getDifficulty() != Difficulty.PEACEFUL) {
+- LOGGER.info("Villager {} was struck by lightning {}.", this, lightning);
+- Witch witch = EntityType.WITCH.create(level);
+- if (witch != null) {
+- witch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+- witch.finalizeSpawn(level, level.getCurrentDifficultyAt(witch.blockPosition()), MobSpawnType.CONVERSION, null, null);
+- witch.setNoAi(this.isNoAi());
++ Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightning);
++ Witch entitywitch = (Witch) EntityType.WITCH.create(level);
++
++ if (entitywitch != null) {
++ entitywitch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
++ entitywitch.finalizeSpawn(level, level.getCurrentDifficultyAt(entitywitch.blockPosition()), EnumMobSpawn.CONVERSION, (GroupDataEntity) 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();
+- level.addFreshEntityWithPassengers(witch);
++ entitywitch.setPersistenceRequired();
++ // CraftBukkit start
++ if (CraftEventFactory.callEntityTransformEvent(this, entitywitch, EntityTransformEvent.TransformReason.LIGHTNING).isCancelled()) {
++ return;
++ }
++ level.addFreshEntityWithPassengers(entitywitch, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING);
++ // CraftBukkit end
+ this.releaseAllPois();
+ this.discard();
+ } else {
+@@ -828,6 +867,7 @@
+ } else {
+ super.thunderHit(level, lightning);
+ }
++
+ }
+
+ @Override
+@@ -838,7 +878,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() {
+@@ -850,37 +891,45 @@
+ }
+
+ private int countFoodPointsInInventory() {
+- SimpleContainer inventory = this.getInventory();
+- return FOOD_POINTS.entrySet().stream().mapToInt(entry -> inventory.countItem(entry.getKey()) * entry.getValue()).sum();
++ SimpleContainer inventorysubcontainer = this.getInventory();
++
++ return Villager.FOOD_POINTS.entrySet().stream().mapToInt((entry) -> {
++ return inventorysubcontainer.countItem((Item) entry.getKey()) * (Integer) entry.getValue();
++ }).sum();
+ }
+
+ public boolean hasFarmSeeds() {
+- return this.getInventory().hasAnyMatching(itemStack -> itemStack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS));
++ return this.getInventory().hasAnyMatching((itemstack) -> {
++ return itemstack.is(ItemTags.VILLAGER_PLANTABLE_SEEDS);
++ });
+ }
+
+ @Override
+ protected void updateTrades() {
+- VillagerData villagerData = this.getVillagerData();
+- Int2ObjectMap<VillagerTrades.ItemListing[]> map1;
++ VillagerData villagerdata = this.getVillagerData();
++ Int2ObjectMap int2objectmap;
++
+ if (this.level().enabledFeatures().contains(FeatureFlags.TRADE_REBALANCE)) {
+- Int2ObjectMap<VillagerTrades.ItemListing[]> map = VillagerTrades.EXPERIMENTAL_TRADES.get(villagerData.getProfession());
+- map1 = map != null ? map : VillagerTrades.TRADES.get(villagerData.getProfession());
++ Int2ObjectMap<VillagerTrades.ItemListing[]> int2objectmap1 = (Int2ObjectMap) VillagerTrades.EXPERIMENTAL_TRADES.get(villagerdata.getProfession());
++
++ int2objectmap = int2objectmap1 != null ? int2objectmap1 : (Int2ObjectMap) VillagerTrades.TRADES.get(villagerdata.getProfession());
+ } else {
+- map1 = VillagerTrades.TRADES.get(villagerData.getProfession());
++ int2objectmap = (Int2ObjectMap) VillagerTrades.TRADES.get(villagerdata.getProfession());
+ }
+
+- if (map1 != null && !map1.isEmpty()) {
+- VillagerTrades.ItemListing[] itemListings = map1.get(villagerData.getLevel());
+- if (itemListings != null) {
+- MerchantOffers offers = this.getOffers();
+- this.addOffersFromItemListings(offers, itemListings, 2);
++ 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, 2);
+ }
+ }
+ }
+
+ public void gossip(ServerLevel serverLevel, Villager target, long gameTime) {
+- if ((gameTime < this.lastGossipTime || gameTime >= this.lastGossipTime + 1200L)
+- && (gameTime < target.lastGossipTime || gameTime >= target.lastGossipTime + 1200L)) {
++ if ((gameTime < this.lastGossipTime || gameTime >= this.lastGossipTime + 1200L) && (gameTime < target.lastGossipTime || gameTime >= target.lastGossipTime + 1200L)) {
+ this.gossips.transferFrom(target.gossips, this.random, 10);
+ this.lastGossipTime = gameTime;
+ target.lastGossipTime = gameTime;
+@@ -889,33 +938,34 @@
+ }
+
+ private void maybeDecayGossip() {
+- long gameTime = this.level().getGameTime();
++ long i = this.level().getGameTime();
++
+ if (this.lastGossipDecayTime == 0L) {
+- this.lastGossipDecayTime = gameTime;
+- } else if (gameTime >= this.lastGossipDecayTime + 24000L) {
++ this.lastGossipDecayTime = i;
++ } else if (i >= this.lastGossipDecayTime + 24000L) {
+ this.gossips.decay();
+- this.lastGossipDecayTime = gameTime;
++ this.lastGossipDecayTime = i;
+ }
+ }
+
+- public void spawnGolemIfNeeded(ServerLevel serverLevel, long gameTime, int minVillagerAmount) {
++ public void spawnGolemIfNeeded(ServerLevel serverLevel, long gameTime, int j) {
+ if (this.wantsToSpawnGolem(gameTime)) {
+- AABB aABB = this.getBoundingBox().inflate(10.0, 10.0, 10.0);
+- List<Villager> entitiesOfClass = serverLevel.getEntitiesOfClass(Villager.class, aABB);
+- List<Villager> list = entitiesOfClass.stream().filter(villager -> villager.wantsToSpawnGolem(gameTime)).limit(5L).collect(Collectors.toList());
+- if (list.size() >= minVillagerAmount) {
+- if (!SpawnUtil.trySpawnMob(
+- EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, serverLevel, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM
+- )
+- .isEmpty()) {
+- entitiesOfClass.forEach(GolemSensor::golemDetected);
++ AABB axisalignedbb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
++ List<Villager> list = serverLevel.getEntitiesOfClass(Villager.class, axisalignedbb);
++ List<Villager> list1 = (List) list.stream().filter((entityvillager) -> {
++ return entityvillager.wantsToSpawnGolem(gameTime);
++ }).limit(5L).collect(Collectors.toList());
++
++ if (list1.size() >= j) {
++ if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, EnumMobSpawn.MOB_SUMMONED, serverLevel, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE).isEmpty()) { // CraftBukkit
++ list.forEach(GolemSensor::golemDetected);
+ }
+ }
+ }
+ }
+
+ public boolean wantsToSpawnGolem(long gameTime) {
+- return this.golemSpawnConditionsMet(this.level().getGameTime()) && !this.brain.hasMemoryValue(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
++ return !this.golemSpawnConditionsMet(this.level().getGameTime()) ? false : !this.brain.hasMemoryValue(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
+ }
+
+ @Override
+@@ -930,6 +980,7 @@
+ } else if (type == ReputationEventType.VILLAGER_KILLED) {
+ this.gossips.add(target.getUUID(), GossipType.MAJOR_NEGATIVE, 25);
+ }
++
+ }
+
+ @Override
+@@ -951,7 +1002,7 @@
+ }
+
+ public void setGossips(Tag gossip) {
+- this.gossips.update(new Dynamic<>(NbtOps.INSTANCE, gossip));
++ this.gossips.update(new Dynamic(NbtOps.INSTANCE, gossip));
+ }
+
+ @Override
+@@ -963,7 +1014,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);
+ }
+@@ -971,11 +1022,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 gameTime) {
+- Optional<Long> memory = this.brain.getMemory(MemoryModuleType.LAST_SLEPT);
+- return memory.isPresent() && gameTime - memory.get() < 24000L;
++ Optional<Long> optional = this.brain.getMemory(MemoryModuleType.LAST_SLEPT);
++
++ return optional.isPresent() ? gameTime - (Long) optional.get() < 24000L : false;
+ }
+ }