From 3ef33943115d1d6dd08e97b8beb20da2edca3d41 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Fri, 13 Dec 2024 19:25:16 +0100 Subject: [PATCH] More mobs --- .../entity/animal/axolotl/Axolotl.java.patch | 36 +++ .../entity/monster/breeze/Breeze.java.patch | 11 +- .../monster/piglin/AbstractPiglin.java.patch | 19 ++ .../entity/monster/piglin/Piglin.java.patch | 119 ++++++++++ .../entity/monster/piglin/PiglinAi.java.patch | 174 +++++++++++++++ .../entity/animal/axolotl/Axolotl.java.patch | 52 ----- .../monster/piglin/AbstractPiglin.java.patch | 20 -- .../entity/monster/piglin/Piglin.java.patch | 140 ------------ .../entity/monster/piglin/PiglinAi.java.patch | 210 ------------------ 9 files changed, 349 insertions(+), 432 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch rename paper-server/patches/{unapplied => sources}/net/minecraft/world/entity/monster/breeze/Breeze.java.patch (64%) create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/Piglin.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch diff --git a/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch new file mode 100644 index 0000000000..302c9dd462 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch @@ -0,0 +1,36 @@ +--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java ++++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java +@@ -226,7 +_,7 @@ + + @Override + public int getMaxAirSupply() { +- return 6000; ++ return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() + } + + @Override +@@ -426,10 +_,10 @@ + if (effect == null || effect.endsWithin(2399)) { + int i = effect != null ? effect.getDuration() : 0; + int min = Math.min(2400, 100 + i); +- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 0), this); ++ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, min, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit + } + +- player.removeEffect(MobEffects.DIG_SLOWDOWN); ++ player.removeEffect(MobEffects.DIG_SLOWDOWN, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // Paper - Add missing effect cause + } + + @Override +@@ -620,4 +_,11 @@ + return Util.getRandom(variants, random); + } + } ++ ++ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() ++ @Override ++ public int getDefaultMaxAirSupply() { ++ return Axolotl.AXOLOTL_TOTAL_AIR_SUPPLY; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/breeze/Breeze.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch similarity index 64% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/breeze/Breeze.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch index b3c69c8fbb..b0ccae8fcd 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/breeze/Breeze.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/breeze/Breeze.java.patch @@ -1,15 +1,6 @@ --- a/net/minecraft/world/entity/monster/breeze/Breeze.java +++ b/net/minecraft/world/entity/monster/breeze/Breeze.java -@@ -77,7 +77,7 @@ - - @Override - public Brain getBrain() { -- return super.getBrain(); -+ return (Brain) super.getBrain(); // CraftBukkit - decompile error - } - - @Override -@@ -252,6 +252,7 @@ +@@ -250,6 +_,7 @@ @Override public boolean canAttackType(EntityType type) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch new file mode 100644 index 0000000000..d17978051b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java ++++ b/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java +@@ -99,9 +_,14 @@ + } + + protected void finishConversion(ServerLevel serverLevel) { +- this.convertTo( +- EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> mob.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)) ++ net.minecraft.world.entity.Entity converted = this.convertTo( // Paper - Fix issues with mob conversion; reset to prevent event spam ++ EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), mob -> {mob.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0));}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED // CraftBukkit - add spawn and transform reasons + ); ++ // Paper start - Fix issues with mob conversion; reset to prevent event spam ++ if (converted == null) { ++ this.timeInOverworld = 0; ++ } ++ // Paper end - Fix issues with mob conversion + } + + public boolean isAdult() { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch new file mode 100644 index 0000000000..4ba6bdac5e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/Piglin.java.patch @@ -0,0 +1,119 @@ +--- a/net/minecraft/world/entity/monster/piglin/Piglin.java ++++ b/net/minecraft/world/entity/monster/piglin/Piglin.java +@@ -4,15 +_,6 @@ + import com.mojang.serialization.Dynamic; + import java.util.List; + import javax.annotation.Nullable; +-import net.minecraft.core.BlockPos; +-import net.minecraft.nbt.CompoundTag; +-import net.minecraft.network.syncher.EntityDataAccessor; +-import net.minecraft.network.syncher.EntityDataSerializers; +-import net.minecraft.network.syncher.SynchedEntityData; +-import net.minecraft.resources.ResourceLocation; +-import net.minecraft.server.level.ServerLevel; +-import net.minecraft.sounds.SoundEvent; +-import net.minecraft.sounds.SoundEvents; + import net.minecraft.tags.ItemTags; + import net.minecraft.tags.TagKey; + import net.minecraft.util.RandomSource; +@@ -59,6 +_,25 @@ + import net.minecraft.world.level.ServerLevelAccessor; + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.BlockState; ++// CraftBukkit start ++import java.util.stream.Collectors; ++import java.util.HashSet; ++import java.util.Set; ++import net.minecraft.core.BlockPos; ++import net.minecraft.core.registries.BuiltInRegistries; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.nbt.ListTag; ++import net.minecraft.nbt.StringTag; ++import net.minecraft.nbt.Tag; ++import net.minecraft.network.syncher.EntityDataAccessor; ++import net.minecraft.network.syncher.EntityDataSerializers; ++import net.minecraft.network.syncher.SynchedEntityData; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.sounds.SoundEvent; ++import net.minecraft.sounds.SoundEvents; ++import net.minecraft.world.item.Item; ++// CraftBukkit end + + public class Piglin extends AbstractPiglin implements CrossbowAttackMob, InventoryCarrier { + private static final EntityDataAccessor DATA_BABY_ID = SynchedEntityData.defineId(Piglin.class, EntityDataSerializers.BOOLEAN); +@@ -122,6 +_,10 @@ + MemoryModuleType.ATE_RECENTLY, + MemoryModuleType.NEAREST_REPELLENT + ); ++ // CraftBukkit start - Custom bartering and interest list ++ public Set allowedBarterItems = new HashSet<>(); ++ public Set interestItems = new HashSet<>(); ++ // CraftBukkit end + + public Piglin(EntityType entityType, Level level) { + super(entityType, level); +@@ -140,6 +_,14 @@ + } + + this.writeInventoryToTag(compound, this.registryAccess()); ++ // CraftBukkit start ++ ListTag barterList = new ListTag(); ++ this.allowedBarterItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(barterList::add); ++ compound.put("Bukkit.BarterList", barterList); ++ ListTag interestList = new ListTag(); ++ this.interestItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(interestList::add); ++ compound.put("Bukkit.InterestList", interestList); ++ // CraftBukkit end + } + + @Override +@@ -148,6 +_,10 @@ + this.setBaby(compound.getBoolean("IsBaby")); + this.setCannotHunt(compound.getBoolean("CannotHunt")); + this.readInventoryFromTag(compound, this.registryAccess()); ++ // CraftBukkit start ++ this.allowedBarterItems = compound.getList("Bukkit.BarterList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new)); ++ this.interestItems = compound.getList("Bukkit.InterestList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new)); ++ // CraftBukkit end + } + + @VisibleForDebug +@@ -325,7 +_,9 @@ + @Override + protected void finishConversion(ServerLevel serverLevel) { + PiglinAi.cancelAdmiring(serverLevel, this); ++ this.forceDrops = true; // Paper - Add missing forceDrop toggles + this.inventory.removeAllItems().forEach(itemStack -> this.spawnAtLocation(serverLevel, itemStack)); ++ this.forceDrops = false; // Paper - Add missing forceDrop toggles + super.finishConversion(serverLevel); + } + +@@ -400,7 +_,7 @@ + } + + protected void holdInOffHand(ItemStack stack) { +- if (stack.is(PiglinAi.BARTERING_ITEM)) { ++ if (stack.is(PiglinAi.BARTERING_ITEM) || this.allowedBarterItems.contains(stack.getItem())) { // CraftBukkit - Changes to accept custom payment items + this.setItemSlot(EquipmentSlot.OFFHAND, stack); + this.setGuaranteedDrop(EquipmentSlot.OFFHAND); + } else { +@@ -425,15 +_,15 @@ + return false; + } else { + TagKey preferredWeaponType = this.getPreferredWeaponType(); +- boolean flag = PiglinAi.isLovedItem(newItem) || preferredWeaponType != null && newItem.is(preferredWeaponType); +- boolean flag1 = PiglinAi.isLovedItem(currentItem) || preferredWeaponType != null && currentItem.is(preferredWeaponType); ++ boolean flag = PiglinAi.isLovedItem(newItem, this) || preferredWeaponType != null && newItem.is(preferredWeaponType); // CraftBukkit ++ boolean flag1 = PiglinAi.isLovedItem(currentItem, this) || preferredWeaponType != null && currentItem.is(preferredWeaponType); // CraftBukkit + return flag && !flag1 || (flag || !flag1) && super.canReplaceCurrentItem(newItem, currentItem, slot); + } + } + + @Override + protected void pickUpItem(ServerLevel level, ItemEntity entity) { +- this.onItemPickup(entity); ++ // this.onItemPickup(entity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired + PiglinAi.pickUpItem(level, this, entity); + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch new file mode 100644 index 0000000000..524c238be3 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch @@ -0,0 +1,174 @@ +--- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java ++++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java +@@ -70,6 +_,13 @@ + import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; + import net.minecraft.world.level.storage.loot.parameters.LootContextParams; + import net.minecraft.world.phys.Vec3; ++// CraftBukkit start ++import java.util.stream.Collectors; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.entity.EntityRemoveEvent; ++import org.bukkit.event.entity.PiglinBarterEvent; ++// CraftBukkit end + + public class PiglinAi { + public static final int REPELLENT_DETECTION_RANGE_HORIZONTAL = 8; +@@ -328,23 +_,32 @@ + protected static void pickUpItem(ServerLevel level, Piglin piglin, ItemEntity itemEntity) { + stopWalking(piglin); + ItemStack item; +- if (itemEntity.getItem().is(Items.GOLD_NUGGET)) { ++ // CraftBukkit start ++ // Paper start - EntityPickupItemEvent fixes; fix event firing twice ++ if (itemEntity.getItem().is(Items.GOLD_NUGGET)/* && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()*/) { // Paper ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) return; ++ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification ++ // Paper end + piglin.take(itemEntity, itemEntity.getItem().getCount()); + item = itemEntity.getItem(); +- itemEntity.discard(); +- } else { ++ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause ++ } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().getCount() - 1, false).isCancelled()) { ++ piglin.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification + piglin.take(itemEntity, 1); + item = removeOneItemFromItemEntity(itemEntity); ++ } else { ++ return; ++ // CraftBukkit end + } + +- if (isLovedItem(item)) { ++ if (isLovedItem(item, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering + piglin.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); + holdInOffhand(level, piglin, item); + admireGoldItem(piglin); + } else if (isFood(item) && !hasEatenRecently(piglin)) { + eat(piglin); + } else { +- boolean flag = !piglin.equipItemIfPossible(level, item).equals(ItemStack.EMPTY); ++ boolean flag = !piglin.equipItemIfPossible(level, item, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above. + if (!flag) { + putInInventory(piglin, item); + } +@@ -353,7 +_,9 @@ + + private static void holdInOffhand(ServerLevel level, Piglin piglin, ItemStack stack) { + if (isHoldingItemInOffHand(piglin)) { ++ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles + piglin.spawnAtLocation(level, piglin.getItemInHand(InteractionHand.OFF_HAND)); ++ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles + } + + piglin.holdInOffHand(stack); +@@ -363,7 +_,7 @@ + ItemStack item = itemEntity.getItem(); + ItemStack itemStack = item.split(1); + if (item.isEmpty()) { +- itemEntity.discard(); ++ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } else { + itemEntity.setItem(item); + } +@@ -375,9 +_,14 @@ + ItemStack itemInHand = piglin.getItemInHand(InteractionHand.OFF_HAND); + piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + if (piglin.isAdult()) { +- boolean isBarterCurrency = isBarterCurrency(itemInHand); ++ boolean isBarterCurrency = isBarterCurrency(itemInHand, piglin); // CraftBukkit - Changes to allow custom payment for bartering + if (barter && isBarterCurrency) { +- throwItems(piglin, getBarterResponseItems(piglin)); ++ // CraftBukkit start ++ PiglinBarterEvent event = CraftEventFactory.callPiglinBarterEvent(piglin, getBarterResponseItems(piglin), itemInHand); ++ if (!event.isCancelled()) { ++ throwItems(piglin, event.getOutcome().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList())); ++ } ++ // CraftBukkit end + } else if (!isBarterCurrency) { + boolean flag = !piglin.equipItemIfPossible(level, itemInHand).isEmpty(); + if (!flag) { +@@ -388,7 +_,7 @@ + boolean isBarterCurrency = !piglin.equipItemIfPossible(level, itemInHand).isEmpty(); + if (!isBarterCurrency) { + ItemStack mainHandItem = piglin.getMainHandItem(); +- if (isLovedItem(mainHandItem)) { ++ if (isLovedItem(mainHandItem, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering + putInInventory(piglin, mainHandItem); + } else { + throwItems(piglin, Collections.singletonList(mainHandItem)); +@@ -401,7 +_,9 @@ + + protected static void cancelAdmiring(ServerLevel level, Piglin piglin) { + if (isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) { ++ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles + piglin.spawnAtLocation(level, piglin.getOffhandItem()); ++ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles + piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); + } + } +@@ -457,7 +_,7 @@ + return false; + } else if (isAdmiringDisabled(piglin) && piglin.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { + return false; +- } else if (isBarterCurrency(stack)) { ++ } else if (isBarterCurrency(stack, piglin)) { // CraftBukkit + return isNotHoldingLovedItemInOffHand(piglin); + } else { + boolean canAddToInventory = piglin.canAddToInventory(stack); +@@ -466,11 +_,16 @@ + } else if (isFood(stack)) { + return !hasEatenRecently(piglin) && canAddToInventory; + } else { +- return !isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory; ++ return !isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : isNotHoldingLovedItemInOffHand(piglin) && canAddToInventory; // Paper - upstream missed isLovedItem check + } + } + } + ++ // CraftBukkit start - Added method to allow checking for custom payment items ++ protected static boolean isLovedItem(ItemStack item, Piglin piglin) { ++ return PiglinAi.isLovedItem(item) || (piglin.interestItems.contains(item.getItem()) || piglin.allowedBarterItems.contains(item.getItem())); ++ } ++ // CraftBukkit end + protected static boolean isLovedItem(ItemStack item) { + return item.is(ItemTags.PIGLIN_LOVED); + } +@@ -522,6 +_,7 @@ + } + + public static void angerNearbyPiglins(ServerLevel level, Player player, boolean requireLineOfSight) { ++ if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests + List entitiesOfClass = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0)); + entitiesOfClass.stream().filter(PiglinAi::isIdle).filter(piglin -> !requireLineOfSight || BehaviorUtils.canSee(piglin, player)).forEach(piglin -> { + if (level.getGameRules().getBoolean(GameRules.RULE_UNIVERSAL_ANGER)) { +@@ -546,7 +_,7 @@ + } + + protected static boolean canAdmire(Piglin piglin, ItemStack stack) { +- return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack); ++ return !isAdmiringDisabled(piglin) && !isAdmiringItem(piglin) && piglin.isAdult() && isBarterCurrency(stack, piglin); // CraftBukkit + } + + protected static void wasHurtBy(ServerLevel level, Piglin piglin, LivingEntity entity) { +@@ -794,6 +_,11 @@ + return piglin.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); + } + ++ // CraftBukkit start - Changes to allow custom payment for bartering ++ private static boolean isBarterCurrency(ItemStack item, Piglin piglin) { ++ return PiglinAi.isBarterCurrency(item) || piglin.allowedBarterItems.contains(item.getItem()); ++ } ++ // CraftBukkit end + private static boolean isBarterCurrency(ItemStack stack) { + return stack.is(BARTERING_ITEM); + } +@@ -831,7 +_,7 @@ + } + + private static boolean isNotHoldingLovedItemInOffHand(Piglin piglin) { +- return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem()); ++ return piglin.getOffhandItem().isEmpty() || !isLovedItem(piglin.getOffhandItem(), piglin); // CraftBukkit - Changes to allow custom payment for bartering + } + + public static boolean isZombified(EntityType entityType) { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch deleted file mode 100644 index 3923bd7b5c..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/animal/axolotl/Axolotl.java.patch +++ /dev/null @@ -1,52 +0,0 @@ ---- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java -+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java -@@ -67,10 +67,17 @@ - - public class Axolotl extends Animal implements VariantHolder, Bucketable { - -+ // CraftBukkit start - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() -+ @Override -+ public int getDefaultMaxAirSupply() { -+ return Axolotl.AXOLOTL_TOTAL_AIR_SUPPLY; -+ } -+ // CraftBukkit end - public static final int TOTAL_PLAYDEAD_TIME = 200; - private static final int POSE_ANIMATION_TICKS = 10; - protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_ADULT, SensorType.HURT_BY, SensorType.AXOLOTL_ATTACKABLES, SensorType.AXOLOTL_TEMPTATIONS); -- protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.BREED_TARGET, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT, new MemoryModuleType[]{MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.PLAY_DEAD_TICKS, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.HAS_HUNTING_COOLDOWN, MemoryModuleType.IS_PANICKING}); -+ // CraftBukkit - decompile error -+ protected static final ImmutableList> MEMORY_TYPES = ImmutableList.>of(MemoryModuleType.BREED_TARGET, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.LOOK_TARGET, MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.PATH, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.NEAREST_VISIBLE_ADULT, new MemoryModuleType[]{MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.PLAY_DEAD_TICKS, MemoryModuleType.NEAREST_ATTACKABLE, MemoryModuleType.TEMPTING_PLAYER, MemoryModuleType.TEMPTATION_COOLDOWN_TICKS, MemoryModuleType.IS_TEMPTED, MemoryModuleType.HAS_HUNTING_COOLDOWN, MemoryModuleType.IS_PANICKING}); - private static final EntityDataAccessor DATA_VARIANT = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.INT); - private static final EntityDataAccessor DATA_PLAYING_DEAD = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor FROM_BUCKET = SynchedEntityData.defineId(Axolotl.class, EntityDataSerializers.BOOLEAN); -@@ -210,7 +217,7 @@ - - @Override - public int getMaxAirSupply() { -- return 6000; -+ return this.maxAirTicks; // CraftBukkit - SPIGOT-6907: re-implement LivingEntity#setMaximumAir() - } - - @Override -@@ -414,10 +421,10 @@ - int i = mobeffect != null ? mobeffect.getDuration() : 0; - int j = Math.min(2400, 100 + i); - -- player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this); -+ player.addEffect(new MobEffectInstance(MobEffects.REGENERATION, j, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // CraftBukkit - } - -- player.removeEffect(MobEffects.DIG_SLOWDOWN); -+ player.removeEffect(MobEffects.DIG_SLOWDOWN, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.AXOLOTL); // Paper - Add missing effect cause - } - - @Override -@@ -464,7 +471,7 @@ - - @Override - public Brain getBrain() { -- return super.getBrain(); -+ return (Brain) super.getBrain(); // CraftBukkit - decompile error - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch deleted file mode 100644 index 68e189739c..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -+++ b/net/minecraft/world/entity/monster/piglin/AbstractPiglin.java -@@ -100,9 +100,15 @@ - } - - protected void finishConversion(ServerLevel world) { -- this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { -+ net.minecraft.world.entity.Entity converted = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, true, true), (entitypigzombie) -> { // Paper - Fix issues with mob conversion; reset to prevent event spam - entitypigzombie.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); -- }); -+ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.PIGLIN_ZOMBIFIED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.PIGLIN_ZOMBIFIED); // CraftBukkit - add spawn and transform reasons -+ -+ // Paper start - Fix issues with mob conversion; reset to prevent event spam -+ if (converted == null) { -+ this.timeInOverworld = 0; -+ } -+ // Paper end - Fix issues with mob conversion - } - - public boolean isAdult() { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/Piglin.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/Piglin.java.patch deleted file mode 100644 index d238fb349f..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/Piglin.java.patch +++ /dev/null @@ -1,140 +0,0 @@ ---- a/net/minecraft/world/entity/monster/piglin/Piglin.java -+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java -@@ -4,15 +4,6 @@ - import com.mojang.serialization.Dynamic; - import java.util.List; - import javax.annotation.Nullable; --import net.minecraft.core.BlockPos; --import net.minecraft.nbt.CompoundTag; --import net.minecraft.network.syncher.EntityDataAccessor; --import net.minecraft.network.syncher.EntityDataSerializers; --import net.minecraft.network.syncher.SynchedEntityData; --import net.minecraft.resources.ResourceLocation; --import net.minecraft.server.level.ServerLevel; --import net.minecraft.sounds.SoundEvent; --import net.minecraft.sounds.SoundEvents; - import net.minecraft.tags.ItemTags; - import net.minecraft.tags.TagKey; - import net.minecraft.util.RandomSource; -@@ -59,6 +50,25 @@ - import net.minecraft.world.level.ServerLevelAccessor; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; -+// CraftBukkit start -+import java.util.stream.Collectors; -+import java.util.HashSet; -+import java.util.Set; -+import net.minecraft.core.BlockPos; -+import net.minecraft.core.registries.BuiltInRegistries; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.StringTag; -+import net.minecraft.nbt.Tag; -+import net.minecraft.network.syncher.EntityDataAccessor; -+import net.minecraft.network.syncher.EntityDataSerializers; -+import net.minecraft.network.syncher.SynchedEntityData; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.sounds.SoundEvent; -+import net.minecraft.sounds.SoundEvents; -+import net.minecraft.world.item.Item; -+// CraftBukkit end - - public class Piglin extends AbstractPiglin implements CrossbowAttackMob, InventoryCarrier { - -@@ -79,6 +89,10 @@ - public boolean cannotHunt; - protected static final ImmutableList>> SENSOR_TYPES = ImmutableList.of(SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.NEAREST_ITEMS, SensorType.HURT_BY, SensorType.PIGLIN_SPECIFIC_SENSOR); - protected static final ImmutableList> MEMORY_TYPES = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.NEAREST_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ATTACKABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, MemoryModuleType.NEARBY_ADULT_PIGLINS, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.ITEM_PICKUP_COOLDOWN_TICKS, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, new MemoryModuleType[]{MemoryModuleType.WALK_TARGET, MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, MemoryModuleType.ATTACK_TARGET, MemoryModuleType.ATTACK_COOLING_DOWN, MemoryModuleType.INTERACTION_TARGET, MemoryModuleType.PATH, MemoryModuleType.ANGRY_AT, MemoryModuleType.UNIVERSAL_ANGER, MemoryModuleType.AVOID_TARGET, MemoryModuleType.ADMIRING_ITEM, MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM, MemoryModuleType.ADMIRING_DISABLED, MemoryModuleType.DISABLE_WALK_TO_ADMIRE_ITEM, MemoryModuleType.CELEBRATE_LOCATION, MemoryModuleType.DANCING, MemoryModuleType.HUNTED_RECENTLY, MemoryModuleType.NEAREST_VISIBLE_BABY_HOGLIN, MemoryModuleType.NEAREST_VISIBLE_NEMESIS, MemoryModuleType.NEAREST_VISIBLE_ZOMBIFIED, MemoryModuleType.RIDE_TARGET, MemoryModuleType.VISIBLE_ADULT_PIGLIN_COUNT, MemoryModuleType.VISIBLE_ADULT_HOGLIN_COUNT, MemoryModuleType.NEAREST_VISIBLE_HUNTABLE_HOGLIN, MemoryModuleType.NEAREST_TARGETABLE_PLAYER_NOT_WEARING_GOLD, MemoryModuleType.NEAREST_PLAYER_HOLDING_WANTED_ITEM, MemoryModuleType.ATE_RECENTLY, MemoryModuleType.NEAREST_REPELLENT}); -+ // CraftBukkit start - Custom bartering and interest list -+ public Set allowedBarterItems = new HashSet<>(); -+ public Set interestItems = new HashSet<>(); -+ // CraftBukkit end - - public Piglin(EntityType type, Level world) { - super(type, world); -@@ -97,6 +111,14 @@ - } - - this.writeInventoryToTag(nbt, this.registryAccess()); -+ // CraftBukkit start -+ ListTag barterList = new ListTag(); -+ this.allowedBarterItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(barterList::add); -+ nbt.put("Bukkit.BarterList", barterList); -+ ListTag interestList = new ListTag(); -+ this.interestItems.stream().map(BuiltInRegistries.ITEM::getKey).map(ResourceLocation::toString).map(StringTag::valueOf).forEach(interestList::add); -+ nbt.put("Bukkit.InterestList", interestList); -+ // CraftBukkit end - } - - @Override -@@ -105,6 +127,10 @@ - this.setBaby(nbt.getBoolean("IsBaby")); - this.setCannotHunt(nbt.getBoolean("CannotHunt")); - this.readInventoryFromTag(nbt, this.registryAccess()); -+ // CraftBukkit start -+ this.allowedBarterItems = nbt.getList("Bukkit.BarterList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new)); -+ this.interestItems = nbt.getList("Bukkit.InterestList", 8).stream().map(Tag::getAsString).map(ResourceLocation::tryParse).map(BuiltInRegistries.ITEM::getValue).collect(Collectors.toCollection(HashSet::new)); -+ // CraftBukkit end - } - - @VisibleForDebug -@@ -224,7 +250,7 @@ - - @Override - public Brain getBrain() { -- return super.getBrain(); -+ return (Brain) super.getBrain(); // CraftBukkit - Decompile error - } - - @Override -@@ -300,9 +326,11 @@ - @Override - protected void finishConversion(ServerLevel world) { - PiglinAi.cancelAdmiring(world, this); -+ this.forceDrops = true; // Paper - Add missing forceDrop toggles - this.inventory.removeAllItems().forEach((itemstack) -> { - this.spawnAtLocation(world, itemstack); - }); -+ this.forceDrops = false; // Paper - Add missing forceDrop toggles - super.finishConversion(world); - } - -@@ -374,7 +402,7 @@ - } - - protected void holdInOffHand(ItemStack stack) { -- if (stack.is(PiglinAi.BARTERING_ITEM)) { -+ if (stack.is(PiglinAi.BARTERING_ITEM) || this.allowedBarterItems.contains(stack.getItem())) { // CraftBukkit - Changes to accept custom payment items - this.setItemSlot(EquipmentSlot.OFFHAND, stack); - this.setGuaranteedDrop(EquipmentSlot.OFFHAND); - } else { -@@ -401,8 +429,8 @@ - return false; - } else { - TagKey tagkey = this.getPreferredWeaponType(); -- boolean flag = PiglinAi.isLovedItem(newStack) || tagkey != null && newStack.is(tagkey); -- boolean flag1 = PiglinAi.isLovedItem(currentStack) || tagkey != null && currentStack.is(tagkey); -+ boolean flag = PiglinAi.isLovedItem(newStack, this) || tagkey != null && newStack.is(tagkey); // CraftBukkit -+ boolean flag1 = PiglinAi.isLovedItem(currentStack, this) || tagkey != null && currentStack.is(tagkey); // CraftBukkit - - return flag && !flag1 ? true : (!flag && flag1 ? false : super.canReplaceCurrentItem(newStack, currentStack, slot)); - } -@@ -410,7 +438,7 @@ - - @Override - protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) { -- this.onItemPickup(itemEntity); -+ // this.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; call in PiglinAi#pickUpItem after EntityPickupItemEvent is fired - PiglinAi.pickUpItem(world, this, itemEntity); - } - -@@ -431,7 +459,7 @@ - - @Override - protected SoundEvent getAmbientSound() { -- return this.level().isClientSide ? null : (SoundEvent) PiglinAi.getSoundForCurrentActivity(this).orElse((Object) null); -+ return this.level().isClientSide ? null : (SoundEvent) PiglinAi.getSoundForCurrentActivity(this).orElse(null); // CraftBukkit - Decompile error - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch deleted file mode 100644 index 66919128bd..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/piglin/PiglinAi.java.patch +++ /dev/null @@ -1,210 +0,0 @@ ---- a/net/minecraft/world/entity/monster/piglin/PiglinAi.java -+++ b/net/minecraft/world/entity/monster/piglin/PiglinAi.java -@@ -71,6 +71,13 @@ - import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; - import net.minecraft.world.level.storage.loot.parameters.LootContextParams; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import java.util.stream.Collectors; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.craftbukkit.inventory.CraftItemStack; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.PiglinBarterEvent; -+// CraftBukkit end - - public class PiglinAi { - -@@ -166,7 +173,8 @@ - } - - private static void initRideHoglinActivity(Brain brain) { -- brain.addActivityAndRemoveMemoryWhenStopped(Activity.RIDE, 10, ImmutableList.of(Mount.create(0.8F), SetEntityLookTarget.create(PiglinAi::isPlayerHoldingLovedItem, 8.0F), BehaviorBuilder.sequence(BehaviorBuilder.triggerIf(Entity::isPassenger), TriggerGate.triggerOneShuffled(ImmutableList.builder().addAll(PiglinAi.createLookBehaviors()).add(Pair.of(BehaviorBuilder.triggerIf((entitypiglin) -> { -+ // CraftBukkit - decompile error -+ brain.addActivityAndRemoveMemoryWhenStopped(Activity.RIDE, 10, ImmutableList.of(Mount.create(0.8F), SetEntityLookTarget.create(PiglinAi::isPlayerHoldingLovedItem, 8.0F), BehaviorBuilder.sequence(BehaviorBuilder.triggerIf(Entity::isPassenger), TriggerGate.triggerOneShuffled(ImmutableList., Integer>>builder().addAll(PiglinAi.createLookBehaviors()).add(Pair.of(BehaviorBuilder.triggerIf((entitypiglin) -> { - return true; - }), 1)).build())), DismountOrSkipMounting.create(8, PiglinAi::wantsToStopRiding)), MemoryModuleType.RIDE_TARGET); - } -@@ -176,7 +184,7 @@ - } - - private static RunOne createIdleLookBehaviors() { -- return new RunOne<>(ImmutableList.builder().addAll(PiglinAi.createLookBehaviors()).add(Pair.of(new DoNothing(30, 60), 1)).build()); -+ return new RunOne<>(ImmutableList., Integer>>builder().addAll(PiglinAi.createLookBehaviors()).add(Pair.of(new DoNothing(30, 60), 1)).build()); // CraftBukkit - decompile error - } - - private static RunOne createIdleMovementBehaviors() { -@@ -197,13 +205,13 @@ - - protected static void updateActivity(Piglin piglin) { - Brain behaviorcontroller = piglin.getBrain(); -- Activity activity = (Activity) behaviorcontroller.getActiveNonCoreActivity().orElse((Object) null); -+ Activity activity = (Activity) behaviorcontroller.getActiveNonCoreActivity().orElse(null); // CraftBukkit - decompile error - - behaviorcontroller.setActiveActivityToFirstValid(ImmutableList.of(Activity.ADMIRE_ITEM, Activity.FIGHT, Activity.AVOID, Activity.CELEBRATE, Activity.RIDE, Activity.IDLE)); -- Activity activity1 = (Activity) behaviorcontroller.getActiveNonCoreActivity().orElse((Object) null); -+ Activity activity1 = (Activity) behaviorcontroller.getActiveNonCoreActivity().orElse(null); // CraftBukkit - decompile error - - if (activity != activity1) { -- Optional optional = PiglinAi.getSoundForCurrentActivity(piglin); -+ Optional optional = PiglinAi.getSoundForCurrentActivity(piglin); // CraftBukkit - decompile error - - Objects.requireNonNull(piglin); - optional.ifPresent(piglin::makeSound); -@@ -235,23 +243,32 @@ - PiglinAi.stopWalking(piglin); - ItemStack itemstack; - -- if (itemEntity.getItem().is(Items.GOLD_NUGGET)) { -- piglin.take(itemEntity, itemEntity.getItem().getCount()); -- itemstack = itemEntity.getItem(); -- itemEntity.discard(); -- } else { -+ // CraftBukkit start -+ // Paper start - EntityPickupItemEvent fixes; fix event firing twice -+ if (itemEntity.getItem().is(Items.GOLD_NUGGET)/* && !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()*/) { // Paper -+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, 0, false).isCancelled()) return; -+ piglin.onItemPickup(itemEntity); // Paper - moved from Piglin#pickUpItem - call prior to item entity modification -+ // Paper end -+ piglin.take(itemEntity, itemEntity.getItem().getCount()); -+ itemstack = itemEntity.getItem(); -+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause -+ } else if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(piglin, itemEntity, itemEntity.getItem().getCount() - 1, false).isCancelled()) { -+ piglin.onItemPickup(itemEntity); // Paper - EntityPickupItemEvent fixes; moved from Piglin#pickUpItem - call prior to item entity modification - piglin.take(itemEntity, 1); - itemstack = PiglinAi.removeOneItemFromItemEntity(itemEntity); -+ } else { -+ return; - } -+ // CraftBukkit end - -- if (PiglinAi.isLovedItem(itemstack)) { -+ if (PiglinAi.isLovedItem(itemstack, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering - piglin.getBrain().eraseMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); - PiglinAi.holdInOffhand(world, piglin, itemstack); - PiglinAi.admireGoldItem(piglin); - } else if (PiglinAi.isFood(itemstack) && !PiglinAi.hasEatenRecently(piglin)) { - PiglinAi.eat(piglin); - } else { -- boolean flag = !piglin.equipItemIfPossible(world, itemstack).equals(ItemStack.EMPTY); -+ boolean flag = !piglin.equipItemIfPossible(world, itemstack, null).equals(ItemStack.EMPTY); // CraftBukkit // Paper - pass null item entity to prevent duplicate pickup item event call - called above. - - if (!flag) { - PiglinAi.putInInventory(piglin, itemstack); -@@ -261,7 +278,9 @@ - - private static void holdInOffhand(ServerLevel world, Piglin piglin, ItemStack stack) { - if (PiglinAi.isHoldingItemInOffHand(piglin)) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(world, piglin.getItemInHand(InteractionHand.OFF_HAND)); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles - } - - piglin.holdInOffHand(stack); -@@ -272,7 +291,7 @@ - ItemStack itemstack1 = itemstack.split(1); - - if (itemstack.isEmpty()) { -- stack.discard(); -+ stack.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } else { - stack.setItem(itemstack); - } -@@ -287,9 +306,14 @@ - boolean flag1; - - if (piglin.isAdult()) { -- flag1 = PiglinAi.isBarterCurrency(itemstack); -+ flag1 = PiglinAi.isBarterCurrency(itemstack, piglin); // CraftBukkit - Changes to allow custom payment for bartering - if (barter && flag1) { -- PiglinAi.throwItems(piglin, PiglinAi.getBarterResponseItems(piglin)); -+ // CraftBukkit start -+ PiglinBarterEvent event = CraftEventFactory.callPiglinBarterEvent(piglin, PiglinAi.getBarterResponseItems(piglin), itemstack); -+ if (!event.isCancelled()) { -+ PiglinAi.throwItems(piglin, event.getOutcome().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList())); -+ } -+ // CraftBukkit end - } else if (!flag1) { - boolean flag2 = !piglin.equipItemIfPossible(world, itemstack).isEmpty(); - -@@ -302,7 +326,7 @@ - if (!flag1) { - ItemStack itemstack1 = piglin.getMainHandItem(); - -- if (PiglinAi.isLovedItem(itemstack1)) { -+ if (PiglinAi.isLovedItem(itemstack1, piglin)) { // CraftBukkit - Changes to allow for custom payment in bartering - PiglinAi.putInInventory(piglin, itemstack1); - } else { - PiglinAi.throwItems(piglin, Collections.singletonList(itemstack1)); -@@ -316,7 +340,9 @@ - - protected static void cancelAdmiring(ServerLevel world, Piglin piglin) { - if (PiglinAi.isAdmiringItem(piglin) && !piglin.getOffhandItem().isEmpty()) { -+ piglin.forceDrops = true; // Paper - Add missing forceDrop toggles - piglin.spawnAtLocation(world, piglin.getOffhandItem()); -+ piglin.forceDrops = false; // Paper - Add missing forceDrop toggles - piglin.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY); - } - -@@ -379,15 +405,21 @@ - return false; - } else if (PiglinAi.isAdmiringDisabled(piglin) && piglin.getBrain().hasMemoryValue(MemoryModuleType.ATTACK_TARGET)) { - return false; -- } else if (PiglinAi.isBarterCurrency(stack)) { -+ } else if (PiglinAi.isBarterCurrency(stack, piglin)) { // CraftBukkit - return PiglinAi.isNotHoldingLovedItemInOffHand(piglin); - } else { - boolean flag = piglin.canAddToInventory(stack); - -- return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); -+ return stack.is(Items.GOLD_NUGGET) ? flag : (PiglinAi.isFood(stack) ? !PiglinAi.hasEatenRecently(piglin) && flag : (!PiglinAi.isLovedItem(stack, piglin) ? piglin.canReplaceCurrentItem(stack) : PiglinAi.isNotHoldingLovedItemInOffHand(piglin) && flag)); // Paper - upstream missed isLovedItem check - } - } - -+ // CraftBukkit start - Added method to allow checking for custom payment items -+ protected static boolean isLovedItem(ItemStack itemstack, Piglin piglin) { -+ return PiglinAi.isLovedItem(itemstack) || (piglin.interestItems.contains(itemstack.getItem()) || piglin.allowedBarterItems.contains(itemstack.getItem())); -+ } -+ // CraftBukkit end -+ - protected static boolean isLovedItem(ItemStack stack) { - return stack.is(ItemTags.PIGLIN_LOVED); - } -@@ -451,6 +483,7 @@ - } - - public static void angerNearbyPiglins(ServerLevel world, Player player, boolean blockOpen) { -+ if (!player.level().paperConfig().entities.behavior.piglinsGuardChests) return; // Paper - Config option for Piglins guarding chests - List list = player.level().getEntitiesOfClass(Piglin.class, player.getBoundingBox().inflate(16.0D)); - - list.stream().filter(PiglinAi::isIdle).filter((entitypiglin) -> { -@@ -481,7 +514,7 @@ - } - - protected static boolean canAdmire(Piglin piglin, ItemStack nearbyItems) { -- return !PiglinAi.isAdmiringDisabled(piglin) && !PiglinAi.isAdmiringItem(piglin) && piglin.isAdult() && PiglinAi.isBarterCurrency(nearbyItems); -+ return !PiglinAi.isAdmiringDisabled(piglin) && !PiglinAi.isAdmiringItem(piglin) && piglin.isAdult() && PiglinAi.isBarterCurrency(nearbyItems, piglin); // CraftBukkit - } - - protected static void wasHurtBy(ServerLevel world, Piglin piglin, LivingEntity attacker) { -@@ -735,6 +768,12 @@ - return entity.getBrain().hasMemoryValue(MemoryModuleType.ADMIRING_ITEM); - } - -+ // CraftBukkit start - Changes to allow custom payment for bartering -+ private static boolean isBarterCurrency(ItemStack itemstack, Piglin piglin) { -+ return PiglinAi.isBarterCurrency(itemstack) || piglin.allowedBarterItems.contains(itemstack.getItem()); -+ } -+ // CraftBukkit end -+ - private static boolean isBarterCurrency(ItemStack stack) { - return stack.is(PiglinAi.BARTERING_ITEM); - } -@@ -772,7 +811,7 @@ - } - - private static boolean isNotHoldingLovedItemInOffHand(Piglin piglin) { -- return piglin.getOffhandItem().isEmpty() || !PiglinAi.isLovedItem(piglin.getOffhandItem()); -+ return piglin.getOffhandItem().isEmpty() || !PiglinAi.isLovedItem(piglin.getOffhandItem(), piglin); // CraftBukkit - Changes to allow custom payment for bartering - } - - public static boolean isZombified(EntityType entityType) {