aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-spigotflower/net/minecraft/world/entity/npc')
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/AbstractVillager.java.patch330
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/InventoryCarrier.java.patch62
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/Villager.java.patch1032
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTrader.java.patch356
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch193
5 files changed, 1973 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/AbstractVillager.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/AbstractVillager.java.patch
new file mode 100644
index 0000000000..bbff4dd88b
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/AbstractVillager.java.patch
@@ -0,0 +1,330 @@
+--- a/net/minecraft/world/entity/npc/AbstractVillager.java
++++ b/net/minecraft/world/entity/npc/AbstractVillager.java
+@@ -20,11 +20,11 @@
+ import net.minecraft.world.entity.AgeableMob;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntityDimensions;
++import net.minecraft.world.entity.EntityPose;
+ import net.minecraft.world.entity.EntityType;
+-import net.minecraft.world.entity.MobSpawnType;
+-import net.minecraft.world.entity.Pose;
++import net.minecraft.world.entity.EnumMobSpawn;
++import net.minecraft.world.entity.GroupDataEntity;
+ import net.minecraft.world.entity.SlotAccess;
+-import net.minecraft.world.entity.SpawnGroupData;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.item.trading.Merchant;
+@@ -34,9 +34,23 @@
+ import net.minecraft.world.level.ServerLevelAccessor;
+ import net.minecraft.world.level.pathfinder.BlockPathTypes;
+ import net.minecraft.world.phys.Vec3;
++// CraftBukkit start
++import org.bukkit.Bukkit;
++import org.bukkit.craftbukkit.inventory.CraftMerchant;
++import org.bukkit.craftbukkit.inventory.CraftMerchantRecipe;
++import org.bukkit.event.entity.VillagerAcquireTradeEvent;
++// CraftBukkit end
+
+-public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, Npc, Merchant {
++public abstract class AbstractVillager extends AgeableMob implements InventoryCarrier, NPC, Merchant {
+
++ // CraftBukkit start
++ private CraftMerchant craftMerchant;
++
++ @Override
++ public CraftMerchant getCraftMerchant() {
++ return (craftMerchant == null) ? craftMerchant = new CraftMerchant(this) : craftMerchant;
++ }
++ // CraftBukkit end
+ private static final EntityDataAccessor<Integer> DATA_UNHAPPY_COUNTER = SynchedEntityData.defineId(AbstractVillager.class, EntityDataSerializers.INT);
+ public static final int VILLAGER_SLOT_OFFSET = 300;
+ private static final int VILLAGER_INVENTORY_SIZE = 8;
+@@ -44,60 +58,54 @@
+ private Player tradingPlayer;
+ @Nullable
+ protected MerchantOffers offers;
+- private final SimpleContainer inventory = new SimpleContainer(8);
++ private final SimpleContainer inventory = new SimpleContainer(8, (org.bukkit.craftbukkit.entity.CraftAbstractVillager) this.getBukkitEntity()); // CraftBukkit add argument
+
+- public AbstractVillager(EntityType<? extends AbstractVillager> entitytype, Level level) {
+- super(entitytype, level);
++ public AbstractVillager(EntityType<? extends AbstractVillager> entityType, Level level) {
++ super(entityType, level);
+ this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 16.0F);
+ this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F);
+ }
+
+ @Override
+- @Override
+- public SpawnGroupData finalizeSpawn(ServerLevelAccessor serverlevelaccessor, DifficultyInstance difficultyinstance, MobSpawnType mobspawntype, @Nullable SpawnGroupData spawngroupdata, @Nullable CompoundTag compoundtag) {
+- if (spawngroupdata == null) {
+- spawngroupdata = new AgeableMob.AgeableMobGroupData(false);
++ public GroupDataEntity finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EnumMobSpawn reason, @Nullable GroupDataEntity spawnData, @Nullable CompoundTag dataTag) {
++ if (spawnData == null) {
++ spawnData = new AgeableMob.AgeableMobGroupData(false);
+ }
+
+- return super.finalizeSpawn(serverlevelaccessor, difficultyinstance, mobspawntype, (SpawnGroupData) spawngroupdata, compoundtag);
++ return super.finalizeSpawn(level, difficulty, reason, (GroupDataEntity) spawnData, dataTag);
+ }
+
+ public int getUnhappyCounter() {
+ return (Integer) this.entityData.get(AbstractVillager.DATA_UNHAPPY_COUNTER);
+ }
+
+- public void setUnhappyCounter(int i) {
+- this.entityData.set(AbstractVillager.DATA_UNHAPPY_COUNTER, i);
++ public void setUnhappyCounter(int unhappyCounter) {
++ this.entityData.set(AbstractVillager.DATA_UNHAPPY_COUNTER, unhappyCounter);
+ }
+
+ @Override
+- @Override
+ public int getVillagerXp() {
+ return 0;
+ }
+
+ @Override
+- @Override
+- protected float getStandingEyeHeight(Pose pose, EntityDimensions entitydimensions) {
++ protected float getStandingEyeHeight(EntityPose pose, EntityDimensions size) {
+ return this.isBaby() ? 0.81F : 1.62F;
+ }
+
+ @Override
+- @Override
+ protected void defineSynchedData() {
+ super.defineSynchedData();
+ this.entityData.define(AbstractVillager.DATA_UNHAPPY_COUNTER, 0);
+ }
+
+ @Override
+- @Override
+ public void setTradingPlayer(@Nullable Player player) {
+ this.tradingPlayer = player;
+ }
+
+ @Nullable
+ @Override
+- @Override
+ public Player getTradingPlayer() {
+ return this.tradingPlayer;
+ }
+@@ -107,7 +115,6 @@
+ }
+
+ @Override
+- @Override
+ public MerchantOffers getOffers() {
+ if (this.offers == null) {
+ this.offers = new MerchantOffers();
+@@ -118,21 +125,18 @@
+ }
+
+ @Override
+- @Override
+- public void overrideOffers(@Nullable MerchantOffers merchantoffers) {}
++ public void overrideOffers(@Nullable MerchantOffers offers) {}
+
+ @Override
+- @Override
+- public void overrideXp(int i) {}
++ public void overrideXp(int xp) {}
+
+ @Override
+- @Override
+- public void notifyTrade(MerchantOffer merchantoffer) {
+- merchantoffer.increaseUses();
++ public void notifyTrade(MerchantOffer offer) {
++ offer.increaseUses();
+ this.ambientSoundTime = -this.getAmbientSoundInterval();
+- this.rewardTradeXp(merchantoffer);
++ this.rewardTradeXp(offer);
+ if (this.tradingPlayer instanceof ServerPlayer) {
+- CriteriaTriggers.TRADE.trigger((ServerPlayer) this.tradingPlayer, this, merchantoffer.getResult());
++ CriteriaTriggers.TRADE.trigger((ServerPlayer) this.tradingPlayer, this, offer.getResult());
+ }
+
+ }
+@@ -140,29 +144,26 @@
+ protected abstract void rewardTradeXp(MerchantOffer offer);
+
+ @Override
+- @Override
+ public boolean showProgressBar() {
+ return true;
+ }
+
+ @Override
+- @Override
+- public void notifyTradeUpdated(ItemStack itemstack) {
++ public void notifyTradeUpdated(ItemStack stack) {
+ if (!this.level().isClientSide && this.ambientSoundTime > -this.getAmbientSoundInterval() + 20) {
+ this.ambientSoundTime = -this.getAmbientSoundInterval();
+- this.playSound(this.getTradeUpdatedSound(!itemstack.isEmpty()), this.getSoundVolume(), this.getVoicePitch());
++ this.playSound(this.getTradeUpdatedSound(!stack.isEmpty()), this.getSoundVolume(), this.getVoicePitch());
+ }
+
+ }
+
+ @Override
+- @Override
+ public SoundEvent getNotifyTradeSound() {
+ return SoundEvents.VILLAGER_YES;
+ }
+
+- protected SoundEvent getTradeUpdatedSound(boolean flag) {
+- return flag ? SoundEvents.VILLAGER_YES : SoundEvents.VILLAGER_NO;
++ protected SoundEvent getTradeUpdatedSound(boolean isYesSound) {
++ return isYesSound ? SoundEvents.VILLAGER_YES : SoundEvents.VILLAGER_NO;
+ }
+
+ public void playCelebrateSound() {
+@@ -170,35 +171,32 @@
+ }
+
+ @Override
+- @Override
+- public void addAdditionalSaveData(CompoundTag compoundtag) {
+- super.addAdditionalSaveData(compoundtag);
+- MerchantOffers merchantoffers = this.getOffers();
++ public void addAdditionalSaveData(CompoundTag compound) {
++ super.addAdditionalSaveData(compound);
++ MerchantOffers merchantrecipelist = this.getOffers();
+
+- if (!merchantoffers.isEmpty()) {
+- compoundtag.put("Offers", merchantoffers.createTag());
++ if (!merchantrecipelist.isEmpty()) {
++ compound.put("Offers", merchantrecipelist.createTag());
+ }
+
+- this.writeInventoryToTag(compoundtag);
++ this.writeInventoryToTag(compound);
+ }
+
+ @Override
+- @Override
+- public void readAdditionalSaveData(CompoundTag compoundtag) {
+- super.readAdditionalSaveData(compoundtag);
+- if (compoundtag.contains("Offers", 10)) {
+- this.offers = new MerchantOffers(compoundtag.getCompound("Offers"));
++ public void readAdditionalSaveData(CompoundTag compound) {
++ super.readAdditionalSaveData(compound);
++ if (compound.contains("Offers", 10)) {
++ this.offers = new MerchantOffers(compound.getCompound("Offers"));
+ }
+
+- this.readInventoryFromTag(compoundtag);
++ this.readInventoryFromTag(compound);
+ }
+
+ @Nullable
+ @Override
+- @Override
+- public Entity changeDimension(ServerLevel serverlevel) {
++ public Entity changeDimension(ServerLevel server) {
+ this.stopTrading();
+- return super.changeDimension(serverlevel);
++ return super.changeDimension(server);
+ }
+
+ protected void stopTrading() {
+@@ -206,54 +204,59 @@
+ }
+
+ @Override
+- @Override
+- public void die(DamageSource damagesource) {
+- super.die(damagesource);
++ public void die(DamageSource cause) {
++ super.die(cause);
+ this.stopTrading();
+ }
+
+- protected void addParticlesAroundSelf(ParticleOptions particleoptions) {
++ protected void addParticlesAroundSelf(ParticleOptions particleOption) {
+ for (int i = 0; i < 5; ++i) {
+ double d0 = this.random.nextGaussian() * 0.02D;
+ double d1 = this.random.nextGaussian() * 0.02D;
+ double d2 = this.random.nextGaussian() * 0.02D;
+
+- this.level().addParticle(particleoptions, this.getRandomX(1.0D), this.getRandomY() + 1.0D, this.getRandomZ(1.0D), d0, d1, d2);
++ this.level().addParticle(particleOption, this.getRandomX(1.0D), this.getRandomY() + 1.0D, this.getRandomZ(1.0D), d0, d1, d2);
+ }
+
+ }
+
+ @Override
+- @Override
+ public boolean canBeLeashed(Player player) {
+ return false;
+ }
+
+ @Override
+- @Override
+ public SimpleContainer getInventory() {
+ return this.inventory;
+ }
+
+ @Override
+- @Override
+- public SlotAccess getSlot(int i) {
+- int j = i - 300;
++ public SlotAccess getSlot(int slot) {
++ int j = slot - 300;
+
+- return j >= 0 && j < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, j) : super.getSlot(i);
++ return j >= 0 && j < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, j) : super.getSlot(slot);
+ }
+
+ protected abstract void updateTrades();
+
+- protected void addOffersFromItemListings(MerchantOffers merchantoffers, VillagerTrades.ItemListing[] avillagertrades_itemlisting, int i) {
+- ArrayList<VillagerTrades.ItemListing> arraylist = Lists.newArrayList(avillagertrades_itemlisting);
++ protected void addOffersFromItemListings(MerchantOffers givenMerchantOffers, VillagerTrades.ItemListing[] newTrades, int maxNumbers) {
++ ArrayList<VillagerTrades.ItemListing> arraylist = Lists.newArrayList(newTrades);
+ int j = 0;
+
+- while (j < i && !arraylist.isEmpty()) {
+- MerchantOffer merchantoffer = ((VillagerTrades.ItemListing) arraylist.remove(this.random.nextInt(arraylist.size()))).getOffer(this, this.random);
++ while (j < maxNumbers && !arraylist.isEmpty()) {
++ MerchantOffer merchantrecipe = ((VillagerTrades.ItemListing) arraylist.remove(this.random.nextInt(arraylist.size()))).getOffer(this, this.random);
+
+- if (merchantoffer != null) {
+- merchantoffers.add(merchantoffer);
++ if (merchantrecipe != null) {
++ // CraftBukkit start
++ VillagerAcquireTradeEvent event = new VillagerAcquireTradeEvent((org.bukkit.entity.AbstractVillager) getBukkitEntity(), merchantrecipe.asBukkit());
++ // Suppress during worldgen
++ if (this.valid) {
++ Bukkit.getPluginManager().callEvent(event);
++ }
++ if (!event.isCancelled()) {
++ givenMerchantOffers.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft());
++ }
++ // CraftBukkit end
+ ++j;
+ }
+ }
+@@ -261,16 +264,14 @@
+ }
+
+ @Override
+- @Override
+- public Vec3 getRopeHoldPosition(float f) {
+- float f1 = Mth.lerp(f, this.yBodyRotO, this.yBodyRot) * 0.017453292F;
+- Vec3 vec3 = new Vec3(0.0D, this.getBoundingBox().getYsize() - 1.0D, 0.2D);
++ public Vec3 getRopeHoldPosition(float partialTicks) {
++ float f1 = Mth.lerp(partialTicks, this.yBodyRotO, this.yBodyRot) * 0.017453292F;
++ Vec3 vec3d = new Vec3(0.0D, this.getBoundingBox().getYsize() - 1.0D, 0.2D);
+
+- return this.getPosition(f).add(vec3.yRot(-f1));
++ return this.getPosition(partialTicks).add(vec3d.yRot(-f1));
+ }
+
+ @Override
+- @Override
+ public boolean isClientSide() {
+ return this.level().isClientSide;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/InventoryCarrier.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/InventoryCarrier.java.patch
new file mode 100644
index 0000000000..6a380696ae
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/InventoryCarrier.java.patch
@@ -0,0 +1,62 @@
+--- a/net/minecraft/world/entity/npc/InventoryCarrier.java
++++ b/net/minecraft/world/entity/npc/InventoryCarrier.java
+@@ -12,24 +12,31 @@
+
+ SimpleContainer getInventory();
+
+- static void pickUpItem(Mob mob, InventoryCarrier inventorycarrier, ItemEntity itementity) {
+- ItemStack itemstack = itementity.getItem();
++ static void pickUpItem(Mob mob, InventoryCarrier carrier, ItemEntity itemEntity) {
++ ItemStack itemstack = itemEntity.getItem();
+
+ if (mob.wantsToPickUp(itemstack)) {
+- SimpleContainer simplecontainer = inventorycarrier.getInventory();
+- boolean flag = simplecontainer.canAddItem(itemstack);
++ SimpleContainer inventorysubcontainer = carrier.getInventory();
++ boolean flag = inventorysubcontainer.canAddItem(itemstack);
+
+ if (!flag) {
+ return;
+ }
+
+- mob.onItemPickup(itementity);
++ // CraftBukkit start
++ ItemStack remaining = new SimpleContainer(inventorysubcontainer).addItem(itemstack);
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(mob, itemEntity, remaining.getCount(), false).isCancelled()) {
++ return;
++ }
++ // CraftBukkit end
++
++ mob.onItemPickup(itemEntity);
+ int i = itemstack.getCount();
+- ItemStack itemstack1 = simplecontainer.addItem(itemstack);
++ ItemStack itemstack1 = inventorysubcontainer.addItem(itemstack);
+
+- mob.take(itementity, i - itemstack1.getCount());
++ mob.take(itemEntity, i - itemstack1.getCount());
+ if (itemstack1.isEmpty()) {
+- itementity.discard();
++ itemEntity.discard();
+ } else {
+ itemstack.setCount(itemstack1.getCount());
+ }
+@@ -37,14 +44,14 @@
+
+ }
+
+- default void readInventoryFromTag(CompoundTag compoundtag) {
+- if (compoundtag.contains("Inventory", 9)) {
+- this.getInventory().fromTag(compoundtag.getList("Inventory", 10));
++ default void readInventoryFromTag(CompoundTag tag) {
++ if (tag.contains("Inventory", 9)) {
++ this.getInventory().fromTag(tag.getList("Inventory", 10));
+ }
+
+ }
+
+- default void writeInventoryToTag(CompoundTag compoundtag) {
+- compoundtag.put("Inventory", this.getInventory().createTag());
++ default void writeInventoryToTag(CompoundTag tag) {
++ tag.put("Inventory", this.getInventory().createTag());
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/Villager.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/Villager.java.patch
new file mode 100644
index 0000000000..4a2f676dd8
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/Villager.java.patch
@@ -0,0 +1,1032 @@
+--- a/net/minecraft/world/entity/npc/Villager.java
++++ b/net/minecraft/world/entity/npc/Villager.java
+@@ -42,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;
+@@ -51,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;
+@@ -92,6 +92,13 @@
+ 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();
+@@ -125,85 +132,81 @@
+ 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, 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, (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);
+ });
+
+- public Villager(EntityType<? extends Villager> entitytype, Level level) {
+- this(entitytype, level, VillagerType.PLAINS);
++ public Villager(EntityType<? extends Villager> entityType, Level level) {
++ this(entityType, level, VillagerType.PLAINS);
+ }
+
+- public Villager(EntityType<? extends Villager> entitytype, Level level, VillagerType villagertype) {
+- super(entitytype, level);
++ public Villager(EntityType<? extends Villager> entityType, Level level, VillagerType villagerType) {
++ super(entityType, level);
+ 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));
++ this.setVillagerData(this.getVillagerData().setType(villagerType).setProfession(VillagerProfession.NONE));
+ }
+
+ @Override
+- @Override
+ public Brain<Villager> getBrain() {
+- return super.getBrain();
++ return (Brain<Villager>) super.getBrain(); // CraftBukkit - decompile error
+ }
+
+ @Override
+- @Override
+ protected Brain.Provider<Villager> brainProvider() {
+ return Brain.provider(Villager.MEMORY_TYPES, Villager.SENSOR_TYPES);
+ }
+
+ @Override
+- @Override
+ protected Brain<?> makeBrain(Dynamic<?> dynamic) {
+- Brain<Villager> brain = this.brainProvider().makeBrain(dynamic);
++ Brain<Villager> behaviorcontroller = this.brainProvider().makeBrain(dynamic);
+
+- this.registerBrainGoals(brain);
+- return brain;
++ this.registerBrainGoals(behaviorcontroller);
++ return behaviorcontroller;
+ }
+
+- public void refreshBrain(ServerLevel serverlevel) {
+- Brain<Villager> brain = this.getBrain();
++ public void refreshBrain(ServerLevel serverLevel) {
++ Brain<Villager> behaviorcontroller = this.getBrain();
+
+- brain.stopAll(serverlevel, this);
+- this.brain = brain.copyWithoutBehaviors();
++ behaviorcontroller.stopAll(serverLevel, this);
++ this.brain = behaviorcontroller.copyWithoutBehaviors();
+ this.registerBrainGoals(this.getBrain());
+ }
+
+- private void registerBrainGoals(Brain<Villager> brain) {
++ private void registerBrainGoals(Brain<Villager> villagerBrain) {
+ VillagerProfession villagerprofession = this.getVillagerData().getProfession();
+
+ if (this.isBaby()) {
+- brain.setSchedule(Schedule.VILLAGER_BABY);
+- brain.addActivity(Activity.PLAY, VillagerGoalPackages.getPlayPackage(0.5F));
++ villagerBrain.setSchedule(Schedule.VILLAGER_BABY);
++ villagerBrain.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)));
++ villagerBrain.setSchedule(Schedule.VILLAGER_DEFAULT);
++ villagerBrain.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.setCoreActivities(ImmutableSet.of(Activity.CORE));
+- brain.setDefaultActivity(Activity.IDLE);
+- brain.setActiveActivityIfPossible(Activity.IDLE);
+- brain.updateActivityFromSchedule(this.level().getDayTime(), this.level().getGameTime());
++ 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);
++ villagerBrain.updateActivityFromSchedule(this.level().getDayTime(), this.level().getGameTime());
+ }
+
+ @Override
+- @Override
+ protected void ageBoundaryReached() {
+ super.ageBoundaryReached();
+ if (this.level() instanceof ServerLevel) {
+@@ -221,7 +224,6 @@
+ }
+
+ @Override
+- @Override
+ protected void customServerAiStep() {
+ this.level().getProfiler().push("villagerBrain");
+ this.getBrain().tick((ServerLevel) this.level(), this);
+@@ -238,7 +240,7 @@
+ 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
+ }
+ }
+
+@@ -264,7 +266,6 @@
+ }
+
+ @Override
+- @Override
+ public void tick() {
+ super.tick();
+ if (this.getUnhappyCounter() > 0) {
+@@ -275,9 +276,8 @@
+ }
+
+ @Override
+- @Override
+- public InteractionResult mobInteract(Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResult mobInteract(Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+ if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isSleeping()) {
+ if (this.isBaby()) {
+@@ -286,7 +286,7 @@
+ } else {
+ boolean flag = this.getOffers().isEmpty();
+
+- if (interactionhand == InteractionHand.MAIN_HAND) {
++ if (hand == EnumHand.MAIN_HAND) {
+ if (flag && !this.level().isClientSide) {
+ this.setUnhappy();
+ }
+@@ -305,11 +305,11 @@
+ }
+ }
+ } else {
+- return super.mobInteract(player, interactionhand);
++ 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());
+@@ -324,7 +324,6 @@
+ }
+
+ @Override
+- @Override
+ public void setTradingPlayer(@Nullable Player player) {
+ boolean flag = this.getTradingPlayer() != null && player == null;
+
+@@ -336,7 +335,6 @@
+ }
+
+ @Override
+- @Override
+ protected void stopTrading() {
+ super.stopTrading();
+ this.resetSpecialPrices();
+@@ -346,21 +344,19 @@
+ Iterator iterator = this.getOffers().iterator();
+
+ while (iterator.hasNext()) {
+- MerchantOffer merchantoffer = (MerchantOffer) iterator.next();
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+- merchantoffer.resetSpecialPriceDiff();
++ merchantrecipe.resetSpecialPriceDiff();
+ }
+
+ }
+
+ @Override
+- @Override
+ public boolean canRestock() {
+ return true;
+ }
+
+ @Override
+- @Override
+ public boolean isClientSide() {
+ return this.level().isClientSide;
+ }
+@@ -370,9 +366,15 @@
+ Iterator iterator = this.getOffers().iterator();
+
+ while (iterator.hasNext()) {
+- MerchantOffer merchantoffer = (MerchantOffer) iterator.next();
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+- merchantoffer.resetUses();
++ // 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();
+@@ -381,11 +383,11 @@
+ }
+
+ private void resendOffersToTradingPlayer() {
+- MerchantOffers merchantoffers = this.getOffers();
+- Player player = this.getTradingPlayer();
++ MerchantOffers merchantrecipelist = this.getOffers();
++ Player entityhuman = this.getTradingPlayer();
+
+- if (player != null && !merchantoffers.isEmpty()) {
+- player.sendMerchantOffers(player.containerMenu.containerId, merchantoffers, this.getVillagerData().getLevel(), this.getVillagerXp(), this.showProgressBar(), this.canRestock());
++ if (entityhuman != null && !merchantrecipelist.isEmpty()) {
++ entityhuman.sendMerchantOffers(entityhuman.containerMenu.containerId, merchantrecipelist, this.getVillagerData().getLevel(), this.getVillagerXp(), this.showProgressBar(), this.canRestock());
+ }
+
+ }
+@@ -393,15 +395,15 @@
+ private boolean needsToRestock() {
+ Iterator iterator = this.getOffers().iterator();
+
+- MerchantOffer merchantoffer;
++ MerchantOffer merchantrecipe;
+
+ do {
+ if (!iterator.hasNext()) {
+ return false;
+ }
+
+- merchantoffer = (MerchantOffer) iterator.next();
+- } while (!merchantoffer.needsRestock());
++ merchantrecipe = (MerchantOffer) iterator.next();
++ } while (!merchantrecipe.needsRestock());
+
+ return true;
+ }
+@@ -439,9 +441,15 @@
+ Iterator iterator = this.getOffers().iterator();
+
+ while (iterator.hasNext()) {
+- MerchantOffer merchantoffer = (MerchantOffer) iterator.next();
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+- merchantoffer.resetUses();
++ // 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
+ }
+ }
+
+@@ -456,9 +464,9 @@
+ Iterator iterator = this.getOffers().iterator();
+
+ while (iterator.hasNext()) {
+- MerchantOffer merchantoffer = (MerchantOffer) iterator.next();
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+- merchantoffer.updateDemand();
++ merchantrecipe.updateDemand();
+ }
+
+ }
+@@ -470,157 +478,147 @@
+ Iterator iterator = this.getOffers().iterator();
+
+ while (iterator.hasNext()) {
+- MerchantOffer merchantoffer = (MerchantOffer) iterator.next();
++ MerchantOffer merchantrecipe = (MerchantOffer) iterator.next();
+
+- merchantoffer.addToSpecialPriceDiff(-Mth.floor((float) i * merchantoffer.getPriceMultiplier()));
++ 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();
+
+ while (iterator1.hasNext()) {
+- MerchantOffer merchantoffer1 = (MerchantOffer) iterator1.next();
++ MerchantOffer merchantrecipe1 = (MerchantOffer) iterator1.next();
+ double d0 = 0.3D + 0.0625D * (double) j;
+- int k = (int) Math.floor(d0 * (double) merchantoffer1.getBaseCostA().getCount());
++ int k = (int) Math.floor(d0 * (double) merchantrecipe1.getBaseCostA().getCount());
+
+- merchantoffer1.addToSpecialPriceDiff(-Math.max(k, 1));
++ merchantrecipe1.addToSpecialPriceDiff(-Math.max(k, 1));
+ }
+ }
+
+ }
+
+ @Override
+- @Override
+ protected void defineSynchedData() {
+ super.defineSynchedData();
+ this.entityData.define(Villager.DATA_VILLAGER_DATA, new VillagerData(VillagerType.PLAINS, VillagerProfession.NONE, 1));
+ }
+
+ @Override
+- @Override
+- public void addAdditionalSaveData(CompoundTag compoundtag) {
+- super.addAdditionalSaveData(compoundtag);
+- DataResult dataresult = VillagerData.CODEC.encodeStart(NbtOps.INSTANCE, this.getVillagerData());
++ public void addAdditionalSaveData(CompoundTag compound) {
++ super.addAdditionalSaveData(compound);
++ 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((tag) -> {
+- compoundtag.put("VillagerData", tag);
++ dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
++ compound.put("VillagerData", nbtbase);
+ });
+- compoundtag.putByte("FoodLevel", (byte) this.foodLevel);
+- compoundtag.put("Gossips", (Tag) this.gossips.store(NbtOps.INSTANCE));
+- compoundtag.putInt("Xp", this.villagerXp);
+- compoundtag.putLong("LastRestock", this.lastRestockGameTime);
+- compoundtag.putLong("LastGossipDecay", this.lastGossipDecayTime);
+- compoundtag.putInt("RestocksToday", this.numberOfRestocksToday);
++ 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);
++ compound.putInt("RestocksToday", this.numberOfRestocksToday);
+ if (this.assignProfessionWhenSpawned) {
+- compoundtag.putBoolean("AssignProfessionWhenSpawned", true);
++ compound.putBoolean("AssignProfessionWhenSpawned", true);
+ }
+
+ }
+
+ @Override
+- @Override
+- public void readAdditionalSaveData(CompoundTag compoundtag) {
+- super.readAdditionalSaveData(compoundtag);
+- if (compoundtag.contains("VillagerData", 10)) {
+- DataResult<VillagerData> dataresult = VillagerData.CODEC.parse(new Dynamic(NbtOps.INSTANCE, compoundtag.get("VillagerData")));
++ 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")));
+ Logger logger = Villager.LOGGER;
+
+ Objects.requireNonNull(logger);
+ dataresult.resultOrPartial(logger::error).ifPresent(this::setVillagerData);
+ }
+
+- if (compoundtag.contains("Offers", 10)) {
+- this.offers = new MerchantOffers(compoundtag.getCompound("Offers"));
++ if (compound.contains("Offers", 10)) {
++ this.offers = new MerchantOffers(compound.getCompound("Offers"));
+ }
+
+- if (compoundtag.contains("FoodLevel", 1)) {
+- this.foodLevel = compoundtag.getByte("FoodLevel");
++ if (compound.contains("FoodLevel", 1)) {
++ this.foodLevel = compound.getByte("FoodLevel");
+ }
+
+- ListTag listtag = compoundtag.getList("Gossips", 10);
++ ListTag nbttaglist = compound.getList("Gossips", 10);
+
+- this.gossips.update(new Dynamic(NbtOps.INSTANCE, listtag));
+- if (compoundtag.contains("Xp", 3)) {
+- this.villagerXp = compoundtag.getInt("Xp");
++ this.gossips.update(new Dynamic(NbtOps.INSTANCE, nbttaglist));
++ if (compound.contains("Xp", 3)) {
++ this.villagerXp = compound.getInt("Xp");
+ }
+
+- this.lastRestockGameTime = compoundtag.getLong("LastRestock");
+- this.lastGossipDecayTime = compoundtag.getLong("LastGossipDecay");
++ this.lastRestockGameTime = compound.getLong("LastRestock");
++ this.lastGossipDecayTime = compound.getLong("LastGossipDecay");
+ this.setCanPickUpLoot(true);
+ if (this.level() instanceof ServerLevel) {
+ this.refreshBrain((ServerLevel) this.level());
+ }
+
+- this.numberOfRestocksToday = compoundtag.getInt("RestocksToday");
+- if (compoundtag.contains("AssignProfessionWhenSpawned")) {
+- this.assignProfessionWhenSpawned = compoundtag.getBoolean("AssignProfessionWhenSpawned");
++ this.numberOfRestocksToday = compound.getInt("RestocksToday");
++ if (compound.contains("AssignProfessionWhenSpawned")) {
++ this.assignProfessionWhenSpawned = compound.getBoolean("AssignProfessionWhenSpawned");
+ }
+
+ }
+
+ @Override
+- @Override
+- public boolean removeWhenFarAway(double d0) {
++ public boolean removeWhenFarAway(double distanceToClosestPlayer) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+- @Override
+ protected SoundEvent getAmbientSound() {
+ return this.isSleeping() ? null : (this.isTrading() ? SoundEvents.VILLAGER_TRADE : SoundEvents.VILLAGER_AMBIENT);
+ }
+
+ @Override
+- @Override
+- protected SoundEvent getHurtSound(DamageSource damagesource) {
++ protected SoundEvent getHurtSound(DamageSource damageSource) {
+ return SoundEvents.VILLAGER_HURT;
+ }
+
+ @Override
+- @Override
+ protected SoundEvent getDeathSound() {
+ return SoundEvents.VILLAGER_DEATH;
+ }
+
+ public void playWorkSound() {
+- SoundEvent soundevent = this.getVillagerData().getProfession().workSound();
++ SoundEvent soundeffect = this.getVillagerData().getProfession().workSound();
+
+- if (soundevent != null) {
+- this.playSound(soundevent, this.getSoundVolume(), this.getVoicePitch());
++ if (soundeffect != null) {
++ this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
+ }
+
+ }
+
+ @Override
+- @Override
+- public void setVillagerData(VillagerData villagerdata) {
++ public void setVillagerData(VillagerData data) {
+ VillagerData villagerdata1 = this.getVillagerData();
+
+- if (villagerdata1.getProfession() != villagerdata.getProfession()) {
++ if (villagerdata1.getProfession() != data.getProfession()) {
+ this.offers = null;
+ }
+
+- this.entityData.set(Villager.DATA_VILLAGER_DATA, villagerdata);
++ this.entityData.set(Villager.DATA_VILLAGER_DATA, data);
+ }
+
+ @Override
+- @Override
+ public VillagerData getVillagerData() {
+ return (VillagerData) this.entityData.get(Villager.DATA_VILLAGER_DATA);
+ }
+
+ @Override
+- @Override
+- protected void rewardTradeXp(MerchantOffer merchantoffer) {
++ protected void rewardTradeXp(MerchantOffer offer) {
+ int i = 3 + this.random.nextInt(4);
+
+- this.villagerXp += merchantoffer.getXp();
++ this.villagerXp += offer.getXp();
+ this.lastTradedPlayer = this.getTradingPlayer();
+ if (this.shouldIncreaseLevel()) {
+ this.updateMerchantTimer = 40;
+@@ -628,14 +626,14 @@
+ i += 5;
+ }
+
+- if (merchantoffer.shouldRewardExp()) {
++ if (offer.shouldRewardExp()) {
+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i));
+ }
+
+ }
+
+- public void setChasing(boolean flag) {
+- this.chasing = flag;
++ public void setChasing(boolean chasing) {
++ this.chasing = chasing;
+ }
+
+ public boolean isChasing() {
+@@ -643,72 +641,70 @@
+ }
+
+ @Override
+- @Override
+- public void setLastHurtByMob(@Nullable LivingEntity livingentity) {
+- if (livingentity != null && this.level() instanceof ServerLevel) {
+- ((ServerLevel) this.level()).onReputationEvent(ReputationEventType.VILLAGER_HURT, livingentity, this);
+- if (this.isAlive() && livingentity instanceof Player) {
++ public void setLastHurtByMob(@Nullable LivingEntity livingBase) {
++ if (livingBase != null && this.level() instanceof ServerLevel) {
++ ((ServerLevel) this.level()).onReputationEvent(ReputationEventType.VILLAGER_HURT, livingBase, this);
++ if (this.isAlive() && livingBase instanceof Player) {
+ this.level().broadcastEntityEvent(this, (byte) 13);
+ }
+ }
+
+- super.setLastHurtByMob(livingentity);
++ super.setLastHurtByMob(livingBase);
+ }
+
+ @Override
+- @Override
+- public void die(DamageSource damagesource) {
+- Villager.LOGGER.info("Villager {} died, message: '{}'", this, damagesource.getLocalizedDeathMessage(this).getString());
+- Entity entity = damagesource.getEntity();
++ public void die(DamageSource cause) {
++ Villager.LOGGER.info("Villager {} died, message: '{}'", this, cause.getLocalizedDeathMessage(this).getString());
++ Entity entity = cause.getEntity();
+
+ if (entity != null) {
+ this.tellWitnessesThatIWasMurdered(entity);
+ }
+
+ this.releaseAllPois();
+- super.die(damagesource);
++ super.die(cause);
+ }
+
+- private void releaseAllPois() {
++ public void releaseAllPois() {
+ this.releasePoi(MemoryModuleType.HOME);
+ this.releasePoi(MemoryModuleType.JOB_SITE);
+ this.releasePoi(MemoryModuleType.POTENTIAL_JOB_SITE);
+ this.releasePoi(MemoryModuleType.MEETING_POINT);
+ }
+
+- private void tellWitnessesThatIWasMurdered(Entity entity) {
+- Level level = this.level();
++ private void tellWitnessesThatIWasMurdered(Entity murderer) {
++ Level world = this.level();
+
+- if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) 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((livingentity) -> {
+- serverlevel.onReputationEvent(ReputationEventType.VILLAGER_KILLED, entity, (ReputationEventHandler) livingentity);
++ nearestvisiblelivingentities.findAll(ReputationEventHandler.class::isInstance).forEach((entityliving) -> {
++ worldserver.onReputationEvent(ReputationEventType.VILLAGER_KILLED, murderer, (ReputationEventHandler) entityliving);
+ });
+ }
+ }
+ }
+
+- public void releasePoi(MemoryModuleType<GlobalPos> memorymoduletype) {
++ public void releasePoi(MemoryModuleType<GlobalPos> moduleType) {
+ if (this.level() instanceof ServerLevel) {
+ MinecraftServer minecraftserver = ((ServerLevel) this.level()).getServer();
+
+- this.brain.getMemory(memorymoduletype).ifPresent((globalpos) -> {
+- ServerLevel serverlevel = minecraftserver.getLevel(globalpos.dimension());
++ this.brain.getMemory(moduleType).ifPresent((globalpos) -> {
++ ServerLevel worldserver = minecraftserver.getLevel(globalpos.dimension());
+
+- if (serverlevel != null) {
+- PoiManager poimanager = serverlevel.getPoiManager();
+- Optional<Holder<PoiType>> optional = poimanager.getType(globalpos.pos());
+- BiPredicate<Villager, Holder<PoiType>> bipredicate = (BiPredicate) Villager.POI_MEMORIES.get(memorymoduletype);
++ 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())) {
+- poimanager.release(globalpos.pos());
+- DebugPackets.sendPoiTicketCountPacket(serverlevel, globalpos.pos());
++ villageplace.release(globalpos.pos());
++ DebugPackets.sendPoiTicketCountPacket(worldserver, globalpos.pos());
+ }
+
+ }
+@@ -717,7 +713,6 @@
+ }
+
+ @Override
+- @Override
+ public boolean canBreed() {
+ return this.foodLevel + this.countFoodPointsInInventory() >= 12 && !this.isSleeping() && this.getAge() == 0;
+ }
+@@ -752,13 +747,13 @@
+ }
+
+ public int getPlayerReputation(Player player) {
+- return this.gossips.getReputation(player.getUUID(), (gossiptype) -> {
++ return this.gossips.getReputation(player.getUUID(), (reputationtype) -> {
+ return true;
+ });
+ }
+
+- private void digestFood(int i) {
+- this.foodLevel -= i;
++ private void digestFood(int qty) {
++ this.foodLevel -= qty;
+ }
+
+ public void eatAndDigestFood() {
+@@ -766,8 +761,8 @@
+ this.digestFood(12);
+ }
+
+- public void setOffers(MerchantOffers merchantoffers) {
+- this.offers = merchantoffers;
++ public void setOffers(MerchantOffers offers) {
++ this.offers = offers;
+ }
+
+ private boolean shouldIncreaseLevel() {
+@@ -776,13 +771,12 @@
+ 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
+- @Override
+ protected Component getTypeName() {
+ String s = this.getType().getDescriptionId();
+
+@@ -790,103 +784,102 @@
+ }
+
+ @Override
+- @Override
+- public void handleEntityEvent(byte b0) {
+- if (b0 == 12) {
++ public void handleEntityEvent(byte id) {
++ if (id == 12) {
+ this.addParticlesAroundSelf(ParticleTypes.HEART);
+- } else if (b0 == 13) {
++ } else if (id == 13) {
+ this.addParticlesAroundSelf(ParticleTypes.ANGRY_VILLAGER);
+- } else if (b0 == 14) {
++ } else if (id == 14) {
+ this.addParticlesAroundSelf(ParticleTypes.HAPPY_VILLAGER);
+- } else if (b0 == 42) {
++ } else if (id == 42) {
+ this.addParticlesAroundSelf(ParticleTypes.SPLASH);
+ } else {
+- super.handleEntityEvent(b0);
++ super.handleEntityEvent(id);
+ }
+
+ }
+
+ @Nullable
+ @Override
+- @Override
+- public SpawnGroupData finalizeSpawn(ServerLevelAccessor serverlevelaccessor, DifficultyInstance difficultyinstance, MobSpawnType mobspawntype, @Nullable SpawnGroupData spawngroupdata, @Nullable CompoundTag compoundtag) {
+- if (mobspawntype == 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 (mobspawntype == MobSpawnType.COMMAND || mobspawntype == MobSpawnType.SPAWN_EGG || MobSpawnType.isSpawner(mobspawntype) || mobspawntype == MobSpawnType.DISPENSER) {
+- this.setVillagerData(this.getVillagerData().setType(VillagerType.byBiome(serverlevelaccessor.getBiome(this.blockPosition()))));
++ 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 (mobspawntype == MobSpawnType.STRUCTURE) {
++ if (reason == EnumMobSpawn.STRUCTURE) {
+ this.assignProfessionWhenSpawned = true;
+ }
+
+- return super.finalizeSpawn(serverlevelaccessor, difficultyinstance, mobspawntype, spawngroupdata, compoundtag);
++ return super.finalizeSpawn(level, difficulty, reason, spawnData, dataTag);
+ }
+
+ @Nullable
+ @Override
+- @Override
+- public Villager getBreedOffspring(ServerLevel serverlevel, AgeableMob ageablemob) {
++ public Villager getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
+ double d0 = this.random.nextDouble();
+ VillagerType villagertype;
+
+ if (d0 < 0.5D) {
+- villagertype = VillagerType.byBiome(serverlevel.getBiome(this.blockPosition()));
++ villagertype = VillagerType.byBiome(level.getBiome(this.blockPosition()));
+ } else if (d0 < 0.75D) {
+ villagertype = this.getVillagerData().getType();
+ } else {
+- villagertype = ((Villager) ageablemob).getVillagerData().getType();
++ villagertype = ((Villager) otherParent).getVillagerData().getType();
+ }
+
+- Villager villager = new Villager(EntityType.VILLAGER, serverlevel, villagertype);
++ Villager entityvillager = new Villager(EntityType.VILLAGER, level, villagertype);
+
+- villager.finalizeSpawn(serverlevel, serverlevel.getCurrentDifficultyAt(villager.blockPosition()), MobSpawnType.BREEDING, (SpawnGroupData) null, (CompoundTag) null);
+- return villager;
++ entityvillager.finalizeSpawn(level, level.getCurrentDifficultyAt(entityvillager.blockPosition()), EnumMobSpawn.BREEDING, (GroupDataEntity) null, (CompoundTag) null);
++ return entityvillager;
+ }
+
+ @Override
+- @Override
+- public void thunderHit(ServerLevel serverlevel, LightningBolt lightningbolt) {
+- if (serverlevel.getDifficulty() != Difficulty.PEACEFUL) {
+- Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightningbolt);
+- Witch witch = (Witch) EntityType.WITCH.create(serverlevel);
++ public void thunderHit(ServerLevel level, LightningBolt lightning) {
++ if (level.getDifficulty() != Difficulty.PEACEFUL) {
++ Villager.LOGGER.info("Villager {} was struck by lightning {}.", this, lightning);
++ Witch entitywitch = (Witch) EntityType.WITCH.create(level);
+
+- if (witch != null) {
+- witch.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+- witch.finalizeSpawn(serverlevel, serverlevel.getCurrentDifficultyAt(witch.blockPosition()), MobSpawnType.CONVERSION, (SpawnGroupData) null, (CompoundTag) null);
+- witch.setNoAi(this.isNoAi());
++ 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();
+- serverlevel.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 {
+- super.thunderHit(serverlevel, lightningbolt);
++ super.thunderHit(level, lightning);
+ }
+ } else {
+- super.thunderHit(serverlevel, lightningbolt);
++ super.thunderHit(level, lightning);
+ }
+
+ }
+
+ @Override
+- @Override
+- protected void pickUpItem(ItemEntity itementity) {
+- InventoryCarrier.pickUpItem(this, this, itementity);
++ protected void pickUpItem(ItemEntity itemEntity) {
++ InventoryCarrier.pickUpItem(this, this, itemEntity);
+ }
+
+ @Override
+- @Override
+- public boolean wantsToPickUp(ItemStack itemstack) {
+- Item item = itemstack.getItem();
++ public boolean wantsToPickUp(ItemStack stack) {
++ Item item = stack.getItem();
+
+- return (Villager.WANTED_ITEMS.contains(item) || this.getVillagerData().getProfession().requestedItems().contains(item)) && this.getInventory().canAddItem(itemstack);
++ return (Villager.WANTED_ITEMS.contains(item) || this.getVillagerData().getProfession().requestedItems().contains(item)) && this.getInventory().canAddItem(stack);
+ }
+
+ public boolean hasExcessFood() {
+@@ -898,10 +891,10 @@
+ }
+
+ private int countFoodPointsInInventory() {
+- SimpleContainer simplecontainer = this.getInventory();
++ SimpleContainer inventorysubcontainer = this.getInventory();
+
+ return Villager.FOOD_POINTS.entrySet().stream().mapToInt((entry) -> {
+- return simplecontainer.countItem((Item) entry.getKey()) * (Integer) entry.getValue();
++ return inventorysubcontainer.countItem((Item) entry.getKey()) * (Integer) entry.getValue();
+ }).sum();
+ }
+
+@@ -912,7 +905,6 @@
+ }
+
+ @Override
+- @Override
+ protected void updateTrades() {
+ VillagerData villagerdata = this.getVillagerData();
+ Int2ObjectMap int2objectmap;
+@@ -926,22 +918,22 @@
+ }
+
+ if (int2objectmap != null && !int2objectmap.isEmpty()) {
+- VillagerTrades.ItemListing[] avillagertrades_itemlisting = (VillagerTrades.ItemListing[]) int2objectmap.get(villagerdata.getLevel());
++ VillagerTrades.ItemListing[] avillagertrades_imerchantrecipeoption = (VillagerTrades.ItemListing[]) int2objectmap.get(villagerdata.getLevel());
+
+- if (avillagertrades_itemlisting != null) {
+- MerchantOffers merchantoffers = this.getOffers();
++ if (avillagertrades_imerchantrecipeoption != null) {
++ MerchantOffers merchantrecipelist = this.getOffers();
+
+- this.addOffersFromItemListings(merchantoffers, avillagertrades_itemlisting, 2);
++ this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, 2);
+ }
+ }
+ }
+
+- public void gossip(ServerLevel serverlevel, Villager villager, long i) {
+- if ((i < this.lastGossipTime || i >= this.lastGossipTime + 1200L) && (i < villager.lastGossipTime || i >= villager.lastGossipTime + 1200L)) {
+- this.gossips.transferFrom(villager.gossips, this.random, 10);
+- this.lastGossipTime = i;
+- villager.lastGossipTime = i;
+- this.spawnGolemIfNeeded(serverlevel, i, 5);
++ public void gossip(ServerLevel serverLevel, Villager target, long gameTime) {
++ 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;
++ this.spawnGolemIfNeeded(serverLevel, gameTime, 5);
+ }
+ }
+
+@@ -956,50 +948,48 @@
+ }
+ }
+
+- public void spawnGolemIfNeeded(ServerLevel serverlevel, long i, int j) {
+- if (this.wantsToSpawnGolem(i)) {
+- AABB aabb = this.getBoundingBox().inflate(10.0D, 10.0D, 10.0D);
+- List<Villager> list = serverlevel.getEntitiesOfClass(Villager.class, aabb);
+- List<Villager> list1 = (List) list.stream().filter((villager) -> {
+- return villager.wantsToSpawnGolem(i);
++ public void spawnGolemIfNeeded(ServerLevel serverLevel, long gameTime, int j) {
++ if (this.wantsToSpawnGolem(gameTime)) {
++ 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, MobSpawnType.MOB_SUMMONED, serverlevel, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM).isEmpty()) {
++ 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 i) {
++ public boolean wantsToSpawnGolem(long gameTime) {
+ return !this.golemSpawnConditionsMet(this.level().getGameTime()) ? false : !this.brain.hasMemoryValue(MemoryModuleType.GOLEM_DETECTED_RECENTLY);
+ }
+
+ @Override
+- @Override
+- public void onReputationEventFrom(ReputationEventType reputationeventtype, Entity entity) {
+- if (reputationeventtype == ReputationEventType.ZOMBIE_VILLAGER_CURED) {
+- this.gossips.add(entity.getUUID(), GossipType.MAJOR_POSITIVE, 20);
+- this.gossips.add(entity.getUUID(), GossipType.MINOR_POSITIVE, 25);
+- } else if (reputationeventtype == ReputationEventType.TRADE) {
+- this.gossips.add(entity.getUUID(), GossipType.TRADING, 2);
+- } else if (reputationeventtype == ReputationEventType.VILLAGER_HURT) {
+- this.gossips.add(entity.getUUID(), GossipType.MINOR_NEGATIVE, 25);
+- } else if (reputationeventtype == ReputationEventType.VILLAGER_KILLED) {
+- this.gossips.add(entity.getUUID(), GossipType.MAJOR_NEGATIVE, 25);
++ public void onReputationEventFrom(ReputationEventType type, Entity target) {
++ if (type == ReputationEventType.ZOMBIE_VILLAGER_CURED) {
++ this.gossips.add(target.getUUID(), GossipType.MAJOR_POSITIVE, 20);
++ this.gossips.add(target.getUUID(), GossipType.MINOR_POSITIVE, 25);
++ } else if (type == ReputationEventType.TRADE) {
++ this.gossips.add(target.getUUID(), GossipType.TRADING, 2);
++ } else if (type == ReputationEventType.VILLAGER_HURT) {
++ this.gossips.add(target.getUUID(), GossipType.MINOR_NEGATIVE, 25);
++ } else if (type == ReputationEventType.VILLAGER_KILLED) {
++ this.gossips.add(target.getUUID(), GossipType.MAJOR_NEGATIVE, 25);
+ }
+
+ }
+
+ @Override
+- @Override
+ public int getVillagerXp() {
+ return this.villagerXp;
+ }
+
+- public void setVillagerXp(int i) {
+- this.villagerXp = i;
++ public void setVillagerXp(int villagerXp) {
++ this.villagerXp = villagerXp;
+ }
+
+ private void resetNumberOfRestocks() {
+@@ -1011,36 +1001,33 @@
+ return this.gossips;
+ }
+
+- public void setGossips(Tag tag) {
+- this.gossips.update(new Dynamic(NbtOps.INSTANCE, tag));
++ public void setGossips(Tag gossip) {
++ this.gossips.update(new Dynamic(NbtOps.INSTANCE, gossip));
+ }
+
+ @Override
+- @Override
+ protected void sendDebugPackets() {
+ super.sendDebugPackets();
+ DebugPackets.sendEntityBrain(this);
+ }
+
+ @Override
+- @Override
+- public void startSleeping(BlockPos blockpos) {
+- super.startSleeping(blockpos);
+- this.brain.setMemory(MemoryModuleType.LAST_SLEPT, (Object) this.level().getGameTime());
++ public void startSleeping(BlockPos pos) {
++ super.startSleeping(pos);
++ 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);
+ }
+
+ @Override
+- @Override
+ public void stopSleeping() {
+ super.stopSleeping();
+- this.brain.setMemory(MemoryModuleType.LAST_WOKEN, (Object) this.level().getGameTime());
++ this.brain.setMemory(MemoryModuleType.LAST_WOKEN, this.level().getGameTime()); // CraftBukkit - decompile error
+ }
+
+- private boolean golemSpawnConditionsMet(long i) {
++ private boolean golemSpawnConditionsMet(long gameTime) {
+ Optional<Long> optional = this.brain.getMemory(MemoryModuleType.LAST_SLEPT);
+
+- return optional.isPresent() ? i - (Long) optional.get() < 24000L : false;
++ return optional.isPresent() ? gameTime - (Long) optional.get() < 24000L : false;
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTrader.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTrader.java.patch
new file mode 100644
index 0000000000..1977fd62f4
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTrader.java.patch
@@ -0,0 +1,356 @@
+--- a/net/minecraft/world/entity/npc/WanderingTrader.java
++++ b/net/minecraft/world/entity/npc/WanderingTrader.java
+@@ -10,7 +10,7 @@
+ import net.minecraft.sounds.SoundEvent;
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.damagesource.DamageSource;
+ import net.minecraft.world.entity.AgeableMob;
+@@ -20,11 +20,11 @@
+ import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
+ import net.minecraft.world.entity.ai.goal.FloatGoal;
+ import net.minecraft.world.entity.ai.goal.Goal;
+-import net.minecraft.world.entity.ai.goal.InteractGoal;
+ import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
+ import net.minecraft.world.entity.ai.goal.LookAtTradingPlayerGoal;
+ import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal;
+ import net.minecraft.world.entity.ai.goal.PanicGoal;
++import net.minecraft.world.entity.ai.goal.PathfinderGoalInteract;
+ import net.minecraft.world.entity.ai.goal.TradeWithPlayerGoal;
+ import net.minecraft.world.entity.ai.goal.UseItemGoal;
+ import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
+@@ -47,26 +47,33 @@
+ import net.minecraft.world.phys.Vec3;
+ import org.apache.commons.lang3.tuple.Pair;
+
+-public class WanderingTrader extends AbstractVillager {
++// CraftBukkit start
++import org.bukkit.Bukkit;
++import org.bukkit.craftbukkit.inventory.CraftMerchantRecipe;
++import org.bukkit.entity.AbstractVillager;
++import org.bukkit.event.entity.VillagerAcquireTradeEvent;
++// CraftBukkit end
+
++public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVillager {
++
+ private static final int NUMBER_OF_TRADE_OFFERS = 5;
+ @Nullable
+ private BlockPos wanderTarget;
+ private int despawnDelay;
+
+- public WanderingTrader(EntityType<? extends WanderingTrader> entitytype, Level level) {
+- super(entitytype, level);
++ public WanderingTrader(EntityType<? extends WanderingTrader> entityType, Level level) {
++ super(entityType, level);
++ this.setDespawnDelay(48000); // CraftBukkit - set default from MobSpawnerTrader
+ }
+
+ @Override
+- @Override
+ protected void registerGoals() {
+ this.goalSelector.addGoal(0, new FloatGoal(this));
+- this.goalSelector.addGoal(0, new UseItemGoal<>(this, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, (wanderingtrader) -> {
+- return this.level().isNight() && !wanderingtrader.isInvisible();
++ this.goalSelector.addGoal(0, new UseItemGoal<>(this, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.INVISIBILITY), SoundEvents.WANDERING_TRADER_DISAPPEARED, (entityvillagertrader) -> {
++ return this.level().isNight() && !entityvillagertrader.isInvisible();
+ }));
+- this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (wanderingtrader) -> {
+- return this.level().isDay() && wanderingtrader.isInvisible();
++ this.goalSelector.addGoal(0, new UseItemGoal<>(this, new ItemStack(Items.MILK_BUCKET), SoundEvents.WANDERING_TRADER_REAPPEARED, (entityvillagertrader) -> {
++ return this.level().isDay() && entityvillagertrader.isInvisible();
+ }));
+ this.goalSelector.addGoal(1, new TradeWithPlayerGoal(this));
+ this.goalSelector.addGoal(1, new AvoidEntityGoal<>(this, Zombie.class, 8.0F, 0.5D, 0.5D));
+@@ -81,30 +88,27 @@
+ this.goalSelector.addGoal(2, new WanderingTrader.WanderToPositionGoal(this, 2.0D, 0.35D));
+ this.goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.35D));
+ this.goalSelector.addGoal(8, new WaterAvoidingRandomStrollGoal(this, 0.35D));
+- this.goalSelector.addGoal(9, new InteractGoal(this, Player.class, 3.0F, 1.0F));
++ this.goalSelector.addGoal(9, new PathfinderGoalInteract(this, Player.class, 3.0F, 1.0F));
+ this.goalSelector.addGoal(10, new LookAtPlayerGoal(this, Mob.class, 8.0F));
+ }
+
+ @Nullable
+ @Override
+- @Override
+- public AgeableMob getBreedOffspring(ServerLevel serverlevel, AgeableMob ageablemob) {
++ public AgeableMob getBreedOffspring(ServerLevel level, AgeableMob otherParent) {
+ return null;
+ }
+
+ @Override
+- @Override
+ public boolean showProgressBar() {
+ return false;
+ }
+
+ @Override
+- @Override
+- public InteractionResult mobInteract(Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResult mobInteract(Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+ if (!itemstack.is(Items.VILLAGER_SPAWN_EGG) && this.isAlive() && !this.isTrading() && !this.isBaby()) {
+- if (interactionhand == InteractionHand.MAIN_HAND) {
++ if (hand == EnumHand.MAIN_HAND) {
+ player.awardStat(Stats.TALKED_TO_VILLAGER);
+ }
+
+@@ -119,29 +123,37 @@
+ return InteractionResult.sidedSuccess(this.level().isClientSide);
+ }
+ } else {
+- return super.mobInteract(player, interactionhand);
++ return super.mobInteract(player, hand);
+ }
+ }
+
+ @Override
+- @Override
+ protected void updateTrades() {
+ if (this.level().enabledFeatures().contains(FeatureFlags.TRADE_REBALANCE)) {
+ this.experimentalUpdateTrades();
+ } else {
+- VillagerTrades.ItemListing[] avillagertrades_itemlisting = (VillagerTrades.ItemListing[]) VillagerTrades.WANDERING_TRADER_TRADES.get(1);
+- VillagerTrades.ItemListing[] avillagertrades_itemlisting1 = (VillagerTrades.ItemListing[]) VillagerTrades.WANDERING_TRADER_TRADES.get(2);
++ VillagerTrades.ItemListing[] avillagertrades_imerchantrecipeoption = (VillagerTrades.ItemListing[]) VillagerTrades.WANDERING_TRADER_TRADES.get(1);
++ VillagerTrades.ItemListing[] avillagertrades_imerchantrecipeoption1 = (VillagerTrades.ItemListing[]) VillagerTrades.WANDERING_TRADER_TRADES.get(2);
+
+- if (avillagertrades_itemlisting != null && avillagertrades_itemlisting1 != null) {
+- MerchantOffers merchantoffers = this.getOffers();
++ if (avillagertrades_imerchantrecipeoption != null && avillagertrades_imerchantrecipeoption1 != null) {
++ MerchantOffers merchantrecipelist = this.getOffers();
+
+- this.addOffersFromItemListings(merchantoffers, avillagertrades_itemlisting, 5);
+- int i = this.random.nextInt(avillagertrades_itemlisting1.length);
+- VillagerTrades.ItemListing villagertrades_itemlisting = avillagertrades_itemlisting1[i];
+- MerchantOffer merchantoffer = villagertrades_itemlisting.getOffer(this, this.random);
++ this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, 5);
++ int i = this.random.nextInt(avillagertrades_imerchantrecipeoption1.length);
++ VillagerTrades.ItemListing villagertrades_imerchantrecipeoption = avillagertrades_imerchantrecipeoption1[i];
++ MerchantOffer merchantrecipe = villagertrades_imerchantrecipeoption.getOffer(this, this.random);
+
+- if (merchantoffer != null) {
+- merchantoffers.add(merchantoffer);
++ if (merchantrecipe != null) {
++ // CraftBukkit start
++ VillagerAcquireTradeEvent event = new VillagerAcquireTradeEvent((AbstractVillager) getBukkitEntity(), merchantrecipe.asBukkit());
++ // Suppress during worldgen
++ if (this.valid) {
++ Bukkit.getPluginManager().callEvent(event);
++ }
++ if (!event.isCancelled()) {
++ merchantrecipelist.add(CraftMerchantRecipe.fromBukkit(event.getRecipe()).toMinecraft());
++ }
++ // CraftBukkit end
+ }
+
+ }
+@@ -149,54 +161,50 @@
+ }
+
+ private void experimentalUpdateTrades() {
+- MerchantOffers merchantoffers = this.getOffers();
++ MerchantOffers merchantrecipelist = this.getOffers();
+ Iterator iterator = VillagerTrades.EXPERIMENTAL_WANDERING_TRADER_TRADES.iterator();
+
+ while (iterator.hasNext()) {
+ Pair<VillagerTrades.ItemListing[], Integer> pair = (Pair) iterator.next();
+- VillagerTrades.ItemListing[] avillagertrades_itemlisting = (VillagerTrades.ItemListing[]) pair.getLeft();
++ VillagerTrades.ItemListing[] avillagertrades_imerchantrecipeoption = (VillagerTrades.ItemListing[]) pair.getLeft();
+
+- this.addOffersFromItemListings(merchantoffers, avillagertrades_itemlisting, (Integer) pair.getRight());
++ this.addOffersFromItemListings(merchantrecipelist, avillagertrades_imerchantrecipeoption, (Integer) pair.getRight());
+ }
+
+ }
+
+ @Override
+- @Override
+- public void addAdditionalSaveData(CompoundTag compoundtag) {
+- super.addAdditionalSaveData(compoundtag);
+- compoundtag.putInt("DespawnDelay", this.despawnDelay);
++ public void addAdditionalSaveData(CompoundTag compound) {
++ super.addAdditionalSaveData(compound);
++ compound.putInt("DespawnDelay", this.despawnDelay);
+ if (this.wanderTarget != null) {
+- compoundtag.put("WanderTarget", NbtUtils.writeBlockPos(this.wanderTarget));
++ compound.put("WanderTarget", NbtUtils.writeBlockPos(this.wanderTarget));
+ }
+
+ }
+
+ @Override
+- @Override
+- public void readAdditionalSaveData(CompoundTag compoundtag) {
+- super.readAdditionalSaveData(compoundtag);
+- if (compoundtag.contains("DespawnDelay", 99)) {
+- this.despawnDelay = compoundtag.getInt("DespawnDelay");
++ public void readAdditionalSaveData(CompoundTag compound) {
++ super.readAdditionalSaveData(compound);
++ if (compound.contains("DespawnDelay", 99)) {
++ this.despawnDelay = compound.getInt("DespawnDelay");
+ }
+
+- if (compoundtag.contains("WanderTarget")) {
+- this.wanderTarget = NbtUtils.readBlockPos(compoundtag.getCompound("WanderTarget"));
++ if (compound.contains("WanderTarget")) {
++ this.wanderTarget = NbtUtils.readBlockPos(compound.getCompound("WanderTarget"));
+ }
+
+ this.setAge(Math.max(0, this.getAge()));
+ }
+
+ @Override
+- @Override
+- public boolean removeWhenFarAway(double d0) {
++ public boolean removeWhenFarAway(double distanceToClosestPlayer) {
+ return false;
+ }
+
+ @Override
+- @Override
+- protected void rewardTradeXp(MerchantOffer merchantoffer) {
+- if (merchantoffer.shouldRewardExp()) {
++ protected void rewardTradeXp(MerchantOffer offer) {
++ if (offer.shouldRewardExp()) {
+ int i = 3 + this.random.nextInt(4);
+
+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i));
+@@ -205,43 +213,37 @@
+ }
+
+ @Override
+- @Override
+ protected SoundEvent getAmbientSound() {
+ return this.isTrading() ? SoundEvents.WANDERING_TRADER_TRADE : SoundEvents.WANDERING_TRADER_AMBIENT;
+ }
+
+ @Override
+- @Override
+- protected SoundEvent getHurtSound(DamageSource damagesource) {
++ protected SoundEvent getHurtSound(DamageSource damageSource) {
+ return SoundEvents.WANDERING_TRADER_HURT;
+ }
+
+ @Override
+- @Override
+ protected SoundEvent getDeathSound() {
+ return SoundEvents.WANDERING_TRADER_DEATH;
+ }
+
+ @Override
+- @Override
+- protected SoundEvent getDrinkingSound(ItemStack itemstack) {
+- return itemstack.is(Items.MILK_BUCKET) ? SoundEvents.WANDERING_TRADER_DRINK_MILK : SoundEvents.WANDERING_TRADER_DRINK_POTION;
++ protected SoundEvent getDrinkingSound(ItemStack stack) {
++ return stack.is(Items.MILK_BUCKET) ? SoundEvents.WANDERING_TRADER_DRINK_MILK : SoundEvents.WANDERING_TRADER_DRINK_POTION;
+ }
+
+ @Override
+- @Override
+- protected SoundEvent getTradeUpdatedSound(boolean flag) {
+- return flag ? SoundEvents.WANDERING_TRADER_YES : SoundEvents.WANDERING_TRADER_NO;
++ protected SoundEvent getTradeUpdatedSound(boolean getYesSound) {
++ return getYesSound ? SoundEvents.WANDERING_TRADER_YES : SoundEvents.WANDERING_TRADER_NO;
+ }
+
+ @Override
+- @Override
+ public SoundEvent getNotifyTradeSound() {
+ return SoundEvents.WANDERING_TRADER_YES;
+ }
+
+- public void setDespawnDelay(int i) {
+- this.despawnDelay = i;
++ public void setDespawnDelay(int despawnDelay) {
++ this.despawnDelay = despawnDelay;
+ }
+
+ public int getDespawnDelay() {
+@@ -249,7 +251,6 @@
+ }
+
+ @Override
+- @Override
+ public void aiStep() {
+ super.aiStep();
+ if (!this.level().isClientSide) {
+@@ -265,8 +266,8 @@
+
+ }
+
+- public void setWanderTarget(@Nullable BlockPos blockpos) {
+- this.wanderTarget = blockpos;
++ public void setWanderTarget(@Nullable BlockPos wanderTarget) {
++ this.wanderTarget = wanderTarget;
+ }
+
+ @Nullable
+@@ -280,48 +281,45 @@
+ final double stopDistance;
+ final double speedModifier;
+
+- WanderToPositionGoal(WanderingTrader wanderingtrader, double d0, double d1) {
+- this.trader = wanderingtrader;
++ WanderToPositionGoal(WanderingTrader entityvillagertrader, double d0, double d1) {
++ this.trader = entityvillagertrader;
+ this.stopDistance = d0;
+ this.speedModifier = d1;
+- this.setFlags(EnumSet.of(Goal.Flag.MOVE));
++ this.setFlags(EnumSet.of(Goal.Type.MOVE));
+ }
+
+ @Override
+- @Override
+ public void stop() {
+ this.trader.setWanderTarget((BlockPos) null);
+ WanderingTrader.this.navigation.stop();
+ }
+
+ @Override
+- @Override
+ public boolean canUse() {
+- BlockPos blockpos = this.trader.getWanderTarget();
++ BlockPos blockposition = this.trader.getWanderTarget();
+
+- return blockpos != null && this.isTooFarAway(blockpos, this.stopDistance);
++ return blockposition != null && this.isTooFarAway(blockposition, this.stopDistance);
+ }
+
+ @Override
+- @Override
+ public void tick() {
+- BlockPos blockpos = this.trader.getWanderTarget();
++ BlockPos blockposition = this.trader.getWanderTarget();
+
+- if (blockpos != null && WanderingTrader.this.navigation.isDone()) {
+- if (this.isTooFarAway(blockpos, 10.0D)) {
+- Vec3 vec3 = (new Vec3((double) blockpos.getX() - this.trader.getX(), (double) blockpos.getY() - this.trader.getY(), (double) blockpos.getZ() - this.trader.getZ())).normalize();
+- Vec3 vec31 = vec3.scale(10.0D).add(this.trader.getX(), this.trader.getY(), this.trader.getZ());
++ if (blockposition != null && WanderingTrader.this.navigation.isDone()) {
++ if (this.isTooFarAway(blockposition, 10.0D)) {
++ Vec3 vec3d = (new Vec3((double) blockposition.getX() - this.trader.getX(), (double) blockposition.getY() - this.trader.getY(), (double) blockposition.getZ() - this.trader.getZ())).normalize();
++ Vec3 vec3d1 = vec3d.scale(10.0D).add(this.trader.getX(), this.trader.getY(), this.trader.getZ());
+
+- WanderingTrader.this.navigation.moveTo(vec31.x, vec31.y, vec31.z, this.speedModifier);
++ WanderingTrader.this.navigation.moveTo(vec3d1.x, vec3d1.y, vec3d1.z, this.speedModifier);
+ } else {
+- WanderingTrader.this.navigation.moveTo((double) blockpos.getX(), (double) blockpos.getY(), (double) blockpos.getZ(), this.speedModifier);
++ WanderingTrader.this.navigation.moveTo((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ(), this.speedModifier);
+ }
+ }
+
+ }
+
+- private boolean isTooFarAway(BlockPos blockpos, double d0) {
+- return !blockpos.closerToCenterThan(this.trader.position(), d0);
++ private boolean isTooFarAway(BlockPos pos, double distance) {
++ return !pos.closerToCenterThan(this.trader.position(), distance);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch
new file mode 100644
index 0000000000..6a29452482
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/npc/WanderingTraderSpawner.java.patch
@@ -0,0 +1,193 @@
+--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
++++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java
+@@ -10,7 +10,7 @@
+ import net.minecraft.util.Mth;
+ import net.minecraft.util.RandomSource;
+ import net.minecraft.world.entity.EntityType;
+-import net.minecraft.world.entity.MobSpawnType;
++import net.minecraft.world.entity.EnumMobSpawn;
+ import net.minecraft.world.entity.SpawnPlacements;
+ import net.minecraft.world.entity.ai.village.poi.PoiManager;
+ import net.minecraft.world.entity.ai.village.poi.PoiTypes;
+@@ -38,24 +38,23 @@
+ private int spawnDelay;
+ private int spawnChance;
+
+- public WanderingTraderSpawner(ServerLevelData serverleveldata) {
+- this.serverLevelData = serverleveldata;
++ public WanderingTraderSpawner(ServerLevelData serverLevelData) {
++ this.serverLevelData = serverLevelData;
+ this.tickDelay = 1200;
+- this.spawnDelay = serverleveldata.getWanderingTraderSpawnDelay();
+- this.spawnChance = serverleveldata.getWanderingTraderSpawnChance();
++ this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay();
++ this.spawnChance = serverLevelData.getWanderingTraderSpawnChance();
+ if (this.spawnDelay == 0 && this.spawnChance == 0) {
+ this.spawnDelay = 24000;
+- serverleveldata.setWanderingTraderSpawnDelay(this.spawnDelay);
++ serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay);
+ this.spawnChance = 25;
+- serverleveldata.setWanderingTraderSpawnChance(this.spawnChance);
++ serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
+ }
+
+ }
+
+ @Override
+- @Override
+- public int tick(ServerLevel serverlevel, boolean flag, boolean flag1) {
+- if (!serverlevel.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) {
++ public int tick(ServerLevel level, boolean spawnHostiles, boolean spawnPassives) {
++ if (!level.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) {
+ return 0;
+ } else if (--this.tickDelay > 0) {
+ return 0;
+@@ -67,7 +66,7 @@
+ return 0;
+ } else {
+ this.spawnDelay = 24000;
+- if (!serverlevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
++ if (!level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) {
+ return 0;
+ } else {
+ int i = this.spawnChance;
+@@ -76,7 +75,7 @@
+ this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance);
+ if (this.random.nextInt(100) > i) {
+ return 0;
+- } else if (this.spawn(serverlevel)) {
++ } else if (this.spawn(level)) {
+ this.spawnChance = 25;
+ return 1;
+ } else {
+@@ -87,41 +86,41 @@
+ }
+ }
+
+- private boolean spawn(ServerLevel serverlevel) {
+- ServerPlayer serverplayer = serverlevel.getRandomPlayer();
++ private boolean spawn(ServerLevel serverLevel) {
++ ServerPlayer entityplayer = serverLevel.getRandomPlayer();
+
+- if (serverplayer == null) {
++ if (entityplayer == null) {
+ return true;
+ } else if (this.random.nextInt(10) != 0) {
+ return false;
+ } else {
+- BlockPos blockpos = serverplayer.blockPosition();
++ BlockPos blockposition = entityplayer.blockPosition();
+ boolean flag = true;
+- PoiManager poimanager = serverlevel.getPoiManager();
+- Optional<BlockPos> optional = poimanager.find((holder) -> {
++ PoiManager villageplace = serverLevel.getPoiManager();
++ Optional<BlockPos> optional = villageplace.find((holder) -> {
+ return holder.is(PoiTypes.MEETING);
+- }, (blockpos1) -> {
++ }, (blockposition1) -> {
+ return true;
+- }, blockpos, 48, PoiManager.Occupancy.ANY);
+- BlockPos blockpos1 = (BlockPos) optional.orElse(blockpos);
+- BlockPos blockpos2 = this.findSpawnPositionNear(serverlevel, blockpos1, 48);
++ }, blockposition, 48, PoiManager.Occupancy.ANY);
++ BlockPos blockposition1 = (BlockPos) optional.orElse(blockposition);
++ BlockPos blockposition2 = this.findSpawnPositionNear(serverLevel, blockposition1, 48);
+
+- if (blockpos2 != null && this.hasEnoughSpace(serverlevel, blockpos2)) {
+- if (serverlevel.getBiome(blockpos2).is(BiomeTags.WITHOUT_WANDERING_TRADER_SPAWNS)) {
++ if (blockposition2 != null && this.hasEnoughSpace(serverLevel, blockposition2)) {
++ if (serverLevel.getBiome(blockposition2).is(BiomeTags.WITHOUT_WANDERING_TRADER_SPAWNS)) {
+ return false;
+ }
+
+- WanderingTrader wanderingtrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(serverlevel, blockpos2, MobSpawnType.EVENT);
++ WanderingTrader entityvillagertrader = (WanderingTrader) EntityType.WANDERING_TRADER.spawn(serverLevel, blockposition2, EnumMobSpawn.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit
+
+- if (wanderingtrader != null) {
++ if (entityvillagertrader != null) {
+ for (int i = 0; i < 2; ++i) {
+- this.tryToSpawnLlamaFor(serverlevel, wanderingtrader, 4);
++ this.tryToSpawnLlamaFor(serverLevel, entityvillagertrader, 4);
+ }
+
+- this.serverLevelData.setWanderingTraderId(wanderingtrader.getUUID());
+- wanderingtrader.setDespawnDelay(48000);
+- wanderingtrader.setWanderTarget(blockpos1);
+- wanderingtrader.restrictTo(blockpos1, 16);
++ this.serverLevelData.setWanderingTraderId(entityvillagertrader.getUUID());
++ // entityvillagertrader.setDespawnDelay(48000); // CraftBukkit - moved to EntityVillagerTrader constructor. This lets the value be modified by plugins on CreatureSpawnEvent
++ entityvillagertrader.setWanderTarget(blockposition1);
++ entityvillagertrader.restrictTo(blockposition1, 16);
+ return true;
+ }
+ }
+@@ -130,49 +129,49 @@
+ }
+ }
+
+- private void tryToSpawnLlamaFor(ServerLevel serverlevel, WanderingTrader wanderingtrader, int i) {
+- BlockPos blockpos = this.findSpawnPositionNear(serverlevel, wanderingtrader.blockPosition(), i);
++ private void tryToSpawnLlamaFor(ServerLevel serverLevel, WanderingTrader trader, int maxDistance) {
++ BlockPos blockposition = this.findSpawnPositionNear(serverLevel, trader.blockPosition(), maxDistance);
+
+- if (blockpos != null) {
+- TraderLlama traderllama = (TraderLlama) EntityType.TRADER_LLAMA.spawn(serverlevel, blockpos, MobSpawnType.EVENT);
++ if (blockposition != null) {
++ TraderLlama entityllamatrader = (TraderLlama) EntityType.TRADER_LLAMA.spawn(serverLevel, blockposition, EnumMobSpawn.EVENT, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL); // CraftBukkit
+
+- if (traderllama != null) {
+- traderllama.setLeashedTo(wanderingtrader, true);
++ if (entityllamatrader != null) {
++ entityllamatrader.setLeashedTo(trader, true);
+ }
+ }
+ }
+
+ @Nullable
+- private BlockPos findSpawnPositionNear(LevelReader levelreader, BlockPos blockpos, int i) {
+- BlockPos blockpos1 = null;
++ private BlockPos findSpawnPositionNear(LevelReader level, BlockPos pos, int maxDistance) {
++ BlockPos blockposition1 = null;
+
+ for (int j = 0; j < 10; ++j) {
+- int k = blockpos.getX() + this.random.nextInt(i * 2) - i;
+- int l = blockpos.getZ() + this.random.nextInt(i * 2) - i;
+- int i1 = levelreader.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
+- BlockPos blockpos2 = new BlockPos(k, i1, l);
++ int k = pos.getX() + this.random.nextInt(maxDistance * 2) - maxDistance;
++ int l = pos.getZ() + this.random.nextInt(maxDistance * 2) - maxDistance;
++ int i1 = level.getHeight(Heightmap.Types.WORLD_SURFACE, k, l);
++ BlockPos blockposition2 = new BlockPos(k, i1, l);
+
+- if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Type.ON_GROUND, levelreader, blockpos2, EntityType.WANDERING_TRADER)) {
+- blockpos1 = blockpos2;
++ if (NaturalSpawner.isSpawnPositionOk(SpawnPlacements.Surface.ON_GROUND, level, blockposition2, EntityType.WANDERING_TRADER)) {
++ blockposition1 = blockposition2;
+ break;
+ }
+ }
+
+- return blockpos1;
++ return blockposition1;
+ }
+
+- private boolean hasEnoughSpace(BlockGetter blockgetter, BlockPos blockpos) {
+- Iterator iterator = BlockPos.betweenClosed(blockpos, blockpos.offset(1, 2, 1)).iterator();
++ private boolean hasEnoughSpace(BlockGetter level, BlockPos pos) {
++ Iterator iterator = BlockPos.betweenClosed(pos, pos.offset(1, 2, 1)).iterator();
+
+- BlockPos blockpos1;
++ BlockPos blockposition1;
+
+ do {
+ if (!iterator.hasNext()) {
+ return true;
+ }
+
+- blockpos1 = (BlockPos) iterator.next();
+- } while (blockgetter.getBlockState(blockpos1).getCollisionShape(blockgetter, blockpos1).isEmpty());
++ blockposition1 = (BlockPos) iterator.next();
++ } while (level.getBlockState(blockposition1).getCollisionShape(level, blockposition1).isEmpty());
+
+ return false;
+ }