--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
@@ -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<Boolean> DATA_BABY_ID = SynchedEntityData.defineId(Piglin.class, EntityDataSerializers.BOOLEAN);
@@ -76,8 +_,8 @@
     private static final float PROBABILITY_OF_SPAWNING_AS_BABY = 0.2F;
     private static final EntityDimensions BABY_DIMENSIONS = EntityType.PIGLIN.getDimensions().scale(0.5F).withEyeHeight(0.97F);
     private static final double PROBABILITY_OF_SPAWNING_WITH_CROSSBOW_INSTEAD_OF_SWORD = 0.5;
-    private final SimpleContainer inventory = new SimpleContainer(8);
-    private boolean cannotHunt;
+    public final SimpleContainer inventory = new SimpleContainer(8);
+    public boolean cannotHunt;
     protected static final ImmutableList<SensorType<? extends Sensor<? super Piglin>>> SENSOR_TYPES = ImmutableList.of(
         SensorType.NEAREST_LIVING_ENTITIES, SensorType.NEAREST_PLAYERS, SensorType.NEAREST_ITEMS, SensorType.HURT_BY, SensorType.PIGLIN_SPECIFIC_SENSOR
     );
@@ -122,6 +_,10 @@
         MemoryModuleType.ATE_RECENTLY,
         MemoryModuleType.NEAREST_REPELLENT
     );
+    // CraftBukkit start - Custom bartering and interest list
+    public Set<Item> allowedBarterItems = new HashSet<>();
+    public Set<Item> interestItems = new HashSet<>();
+    // CraftBukkit end
 
     public Piglin(EntityType<? extends AbstractPiglin> 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);
     }
 
@@ -338,7 +_,7 @@
         return this.isBaby() ? null : ItemTags.PIGLIN_PREFERRED_WEAPONS;
     }
 
-    private boolean isChargingCrossbow() {
+    public boolean isChargingCrossbow() {
         return this.entityData.get(DATA_IS_CHARGING_CROSSBOW);
     }
 
@@ -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<Item> 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);
     }
 
@@ -462,7 +_,7 @@
     }
 
     @Override
-    protected SoundEvent getDeathSound() {
+    public SoundEvent getDeathSound() {
         return SoundEvents.PIGLIN_DEATH;
     }
 
