diff --git a/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/EntityPiglin.patch b/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/EntityPiglin.patch new file mode 100644 index 0000000000..dada9f9a5e --- /dev/null +++ b/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/EntityPiglin.patch @@ -0,0 +1,110 @@ +--- a/net/minecraft/world/entity/monster/piglin/EntityPiglin.java ++++ b/net/minecraft/world/entity/monster/piglin/EntityPiglin.java +@@ -53,6 +53,18 @@ + import net.minecraft.world.level.block.Blocks; + import net.minecraft.world.level.block.state.IBlockData; + ++// CraftBukkit start ++import java.util.stream.Collectors; ++import java.util.HashSet; ++import java.util.Set; ++import net.minecraft.core.IRegistry; ++import net.minecraft.nbt.NBTTagList; ++import net.minecraft.nbt.NBTTagString; ++import net.minecraft.nbt.NBTBase; ++import net.minecraft.resources.MinecraftKey; ++import net.minecraft.world.item.Item; ++// CraftBukkit end ++ + public class EntityPiglin extends EntityPiglinAbstract implements ICrossbow { + + private static final DataWatcherObject bp = DataWatcher.a(EntityPiglin.class, DataWatcherRegistry.i); +@@ -60,10 +72,14 @@ + private static final DataWatcherObject br = DataWatcher.a(EntityPiglin.class, DataWatcherRegistry.i); + private static final UUID bs = UUID.fromString("766bfa64-11f3-11ea-8d71-362b9e155667"); + private static final AttributeModifier bt = new AttributeModifier(EntityPiglin.bs, "Baby speed boost", 0.20000000298023224D, AttributeModifier.Operation.MULTIPLY_BASE); +- private final InventorySubcontainer bu = new InventorySubcontainer(8); ++ public final InventorySubcontainer bu = new InventorySubcontainer(8); // PAIL private -> public + public boolean cannotHunt = false; + protected static final ImmutableList>> d = ImmutableList.of(SensorType.c, SensorType.d, SensorType.b, SensorType.f, SensorType.k); + protected static final ImmutableList> bo = ImmutableList.of(MemoryModuleType.LOOK_TARGET, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.MOBS, MemoryModuleType.VISIBLE_MOBS, MemoryModuleType.NEAREST_VISIBLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_TARGETABLE_PLAYER, MemoryModuleType.NEAREST_VISIBLE_ADULT_PIGLINS, MemoryModuleType.NEARBY_ADULT_PIGLINS, MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, MemoryModuleType.HURT_BY, MemoryModuleType.HURT_BY_ENTITY, MemoryModuleType.WALK_TARGET, new MemoryModuleType[]{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_NEMSIS, 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 EntityPiglin(EntityTypes entitytypes, World world) { + super(entitytypes, world); +@@ -82,6 +98,14 @@ + } + + nbttagcompound.set("Inventory", this.bu.g()); ++ // CraftBukkit start ++ NBTTagList barterList = new NBTTagList(); ++ allowedBarterItems.stream().map(IRegistry.ITEM::getKey).map(MinecraftKey::toString).map(NBTTagString::a).forEach(barterList::add); ++ nbttagcompound.set("Bukkit.BarterList", barterList); ++ NBTTagList interestList = new NBTTagList(); ++ interestItems.stream().map(IRegistry.ITEM::getKey).map(MinecraftKey::toString).map(NBTTagString::a).forEach(interestList::add); ++ nbttagcompound.set("Bukkit.InterestList", interestList); ++ // CraftBukkit end + } + + @Override +@@ -90,6 +114,10 @@ + this.setBaby(nbttagcompound.getBoolean("IsBaby")); + this.v(nbttagcompound.getBoolean("CannotHunt")); + this.bu.a(nbttagcompound.getList("Inventory", 10)); ++ // CraftBukkit start ++ this.allowedBarterItems = nbttagcompound.getList("Bukkit.BarterList", 8).stream().map(NBTBase::asString).map(MinecraftKey::a).map(IRegistry.ITEM::get).collect(Collectors.toCollection(HashSet::new)); ++ this.interestItems = nbttagcompound.getList("Bukkit.InterestList", 8).stream().map(NBTBase::asString).map(MinecraftKey::a).map(IRegistry.ITEM::get).collect(Collectors.toCollection(HashSet::new)); ++ // CraftBukkit end + } + + @Override +@@ -188,7 +216,7 @@ + + @Override + public BehaviorController getBehaviorController() { +- return super.getBehaviorController(); ++ return (BehaviorController) super.getBehaviorController(); // CraftBukkit - Decompile error + } + + @Override +@@ -247,7 +275,7 @@ + @Override + protected void mobTick() { + this.world.getMethodProfiler().enter("piglinBrain"); +- this.getBehaviorController().a((WorldServer) this.world, (EntityLiving) this); ++ this.getBehaviorController().a((WorldServer) this.world, (EntityPiglin) this); // CraftBukkit - decompile error + this.world.getMethodProfiler().exit(); + PiglinAI.b(this); + super.mobTick(); +@@ -330,7 +358,7 @@ + } + + protected void n(ItemStack itemstack) { +- if (itemstack.getItem() == PiglinAI.a) { ++ if (itemstack.getItem() == PiglinAI.a || allowedBarterItems.contains(itemstack.getItem())) { // CraftBukkit - Changes to accept custom payment items + this.setSlot(EnumItemSlot.OFFHAND, itemstack); + this.d(EnumItemSlot.OFFHAND); + } else { +@@ -356,8 +384,8 @@ + if (EnchantmentManager.d(itemstack1)) { + return false; + } else { +- boolean flag = PiglinAI.a(itemstack.getItem()) || itemstack.getItem() == Items.CROSSBOW; +- boolean flag1 = PiglinAI.a(itemstack1.getItem()) || itemstack1.getItem() == Items.CROSSBOW; ++ boolean flag = PiglinAI.isLovedByPiglin(itemstack.getItem(), this) || itemstack.getItem() == Items.CROSSBOW; // CraftBukkit ++ boolean flag1 = PiglinAI.isLovedByPiglin(itemstack1.getItem(), this) || itemstack1.getItem() == Items.CROSSBOW; // CraftBukkit + + return flag && !flag1 ? true : (!flag && flag1 ? false : (this.eM() && itemstack.getItem() != Items.CROSSBOW && itemstack1.getItem() == Items.CROSSBOW ? false : super.a(itemstack, itemstack1))); + } +@@ -386,7 +414,7 @@ + + @Override + protected SoundEffect getSoundAmbient() { +- return this.world.isClientSide ? null : (SoundEffect) PiglinAI.d(this).orElse((Object) null); ++ return this.world.isClientSide ? null : (SoundEffect) PiglinAI.d(this).orElse(null); // CraftBukkit - Decompile error + } + + @Override diff --git a/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/PiglinAI.patch b/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/PiglinAI.patch index 6a040e2db4..b825db994b 100644 --- a/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/PiglinAI.patch +++ b/paper-server/nms-patches/net/minecraft/world/entity/monster/piglin/PiglinAI.patch @@ -1,6 +1,20 @@ --- a/net/minecraft/world/entity/monster/piglin/PiglinAI.java +++ b/net/minecraft/world/entity/monster/piglin/PiglinAI.java -@@ -114,7 +114,8 @@ +@@ -72,6 +72,13 @@ + import net.minecraft.world.level.storage.loot.parameters.LootContextParameters; + import net.minecraft.world.phys.Vec3D; + ++// CraftBukkit start ++import java.util.stream.Collectors; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.entity.PiglinBarterEvent; ++// CraftBukkit end ++ + public class PiglinAI { + + public static final Item a = Items.GOLD_INGOT; +@@ -114,7 +121,8 @@ private static void b(EntityPiglin entitypiglin, BehaviorController behaviorcontroller) { behaviorcontroller.a(Activity.FLIGHT, 10, ImmutableList.of(new BehaviorAttackTargetForget<>((entityliving) -> { return !b(entitypiglin, entityliving); @@ -10,7 +24,7 @@ } private static void c(BehaviorController behaviorcontroller) { -@@ -132,7 +133,8 @@ +@@ -132,7 +140,8 @@ } private static void f(BehaviorController behaviorcontroller) { @@ -20,7 +34,7 @@ } private static BehaviorGateSingle a() { -@@ -140,7 +142,8 @@ +@@ -140,7 +149,8 @@ } private static BehaviorGateSingle b() { @@ -30,7 +44,7 @@ } private static BehaviorWalkAway c() { -@@ -157,10 +160,10 @@ +@@ -157,10 +167,10 @@ protected static void b(EntityPiglin entitypiglin) { BehaviorController behaviorcontroller = entitypiglin.getBehaviorController(); @@ -43,7 +57,7 @@ if (activity != activity1) { d(entitypiglin).ifPresent(entitypiglin::a); -@@ -192,14 +195,18 @@ +@@ -192,25 +202,29 @@ n(entitypiglin); ItemStack itemstack; @@ -64,7 +78,11 @@ Item item = itemstack.getItem(); -@@ -210,7 +217,7 @@ +- if (a(item)) { ++ if (a(entitypiglin, itemstack)) { // CraftBukkit - Changes to allow for custom payment in bartering + entitypiglin.getBehaviorController().removeMemory(MemoryModuleType.TIME_TRYING_TO_REACH_ADMIRE_ITEM); + c(entitypiglin, itemstack); + d((EntityLiving) entitypiglin); } else if (c(item) && !u(entitypiglin)) { s(entitypiglin); } else { @@ -73,7 +91,57 @@ if (!flag) { d(entitypiglin, itemstack); -@@ -412,7 +419,7 @@ +@@ -246,9 +260,14 @@ + boolean flag1; + + if (entitypiglin.eM()) { +- flag1 = b(itemstack.getItem()); ++ flag1 = isBarterItem(itemstack.getItem(), entitypiglin); // CraftBukkit - Changes to allow custom payment for bartering + if (flag && flag1) { +- a(entitypiglin, i(entitypiglin)); ++ // CraftBukkit start ++ PiglinBarterEvent event = CraftEventFactory.callPiglinBarterEvent(entitypiglin, i(entitypiglin), itemstack); ++ if (!event.isCancelled()) { ++ a(entitypiglin, event.getOutcome().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList())); ++ } ++ // CraftBukkit end + } else if (!flag1) { + boolean flag2 = entitypiglin.g(itemstack); + +@@ -261,7 +280,7 @@ + if (!flag1) { + ItemStack itemstack1 = entitypiglin.getItemInMainHand(); + +- if (a(itemstack1.getItem())) { ++ if (isLovedByPiglin(itemstack1.getItem(), entitypiglin)) { // CraftBukkit - Changes to allow for custom payment in bartering + d(entitypiglin, itemstack1); + } else { + a(entitypiglin, Collections.singletonList(itemstack1)); +@@ -338,15 +357,21 @@ + return false; + } else if (x(entitypiglin) && entitypiglin.getBehaviorController().hasMemory(MemoryModuleType.ATTACK_TARGET)) { + return false; +- } else if (b(item)) { ++ } else if (isBarterItem(item, entitypiglin)) { // CraftBukkit + return z(entitypiglin); + } else { + boolean flag = entitypiglin.l(itemstack); + +- return item == Items.GOLD_NUGGET ? flag : (c(item) ? !u(entitypiglin) && flag : (!a(item) ? entitypiglin.o(itemstack) : z(entitypiglin) && flag)); ++ return item == Items.GOLD_NUGGET ? flag : (c(item) ? !u(entitypiglin) && flag : (!isLovedByPiglin(item, entitypiglin) ? entitypiglin.o(itemstack) : z(entitypiglin) && flag)); //CraftBukkit + } + } + ++ // CraftBukkit start - Added method to allow checking for custom payment items ++ protected static boolean isLovedByPiglin(Item item, EntityPiglin piglin) { ++ return a(item) || (piglin.interestItems.contains(item) || piglin.allowedBarterItems.contains(item)); ++ } ++ // CraftBukkit end ++ + protected static boolean a(Item item) { + return item.a((Tag) TagsItem.PIGLIN_LOVED); + } +@@ -412,7 +437,7 @@ } public static void a(EntityHuman entityhuman, boolean flag) { @@ -82,7 +150,16 @@ list.stream().filter(PiglinAI::d).filter((entitypiglin) -> { return !flag || BehaviorUtil.c(entitypiglin, entityhuman); -@@ -648,7 +655,7 @@ +@@ -442,7 +467,7 @@ + } + + protected static boolean b(EntityPiglin entitypiglin, ItemStack itemstack) { +- return !x(entitypiglin) && !v(entitypiglin) && entitypiglin.eM() && b(itemstack.getItem()); ++ return !x(entitypiglin) && !v(entitypiglin) && entitypiglin.eM() && isBarterItem(itemstack.getItem(), entitypiglin); // CraftBukkit + } + + protected static void a(EntityPiglin entitypiglin, EntityLiving entityliving) { +@@ -648,7 +673,7 @@ EntityLiving entityliving = (EntityLiving) behaviorcontroller.getMemory(MemoryModuleType.AVOID_TARGET).get(); EntityTypes entitytypes = entityliving.getEntityType(); @@ -91,7 +168,20 @@ } } -@@ -730,7 +737,7 @@ +@@ -705,6 +730,12 @@ + return entitypiglin.getBehaviorController().hasMemory(MemoryModuleType.ADMIRING_ITEM); + } + ++ // CraftBukkit start - Changes to allow custom payment for bartering ++ private static boolean isBarterItem(Item item, EntityPiglin piglin) { ++ return b(item) || piglin.allowedBarterItems.contains(item); ++ } ++ // CraftBukkit end ++ + private static boolean b(Item item) { + return item == PiglinAI.a; + } +@@ -730,7 +761,7 @@ } public static boolean b(EntityLiving entityliving) { @@ -100,3 +190,12 @@ } private static boolean x(EntityPiglin entitypiglin) { +@@ -746,7 +777,7 @@ + } + + private static boolean z(EntityPiglin entitypiglin) { +- return entitypiglin.getItemInOffHand().isEmpty() || !a(entitypiglin.getItemInOffHand().getItem()); ++ return entitypiglin.getItemInOffHand().isEmpty() || !isLovedByPiglin(entitypiglin.getItemInOffHand().getItem(), entitypiglin); // CraftBukkit - Changes to allow custom payment for bartering + } + + public static boolean a(EntityTypes entitytypes) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java index a224ebf168..0327f3d9e1 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftPiglin.java @@ -1,9 +1,18 @@ package org.bukkit.craftbukkit.entity; +import com.google.common.base.Preconditions; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; import net.minecraft.world.entity.monster.piglin.EntityPiglin; +import net.minecraft.world.item.Item; +import org.bukkit.Material; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import org.bukkit.entity.Piglin; +import org.bukkit.inventory.Inventory; public class CraftPiglin extends CraftPiglinAbstract implements Piglin { @@ -21,6 +30,53 @@ public class CraftPiglin extends CraftPiglinAbstract implements Piglin { getHandle().cannotHunt = flag; } + @Override + public boolean addBarterMaterial(Material material) { + Preconditions.checkArgument(material != null, "material cannot be null"); + + Item item = CraftMagicNumbers.getItem(material); + return getHandle().allowedBarterItems.add(item); + } + + @Override + public boolean removeBarterMaterial(Material material) { + Preconditions.checkArgument(material != null, "material cannot be null"); + + Item item = CraftMagicNumbers.getItem(material); + return getHandle().allowedBarterItems.remove(item); + } + + @Override + public boolean addMaterialOfInterest(Material material) { + Preconditions.checkArgument(material != null, "material cannot be null"); + + Item item = CraftMagicNumbers.getItem(material); + return getHandle().interestItems.add(item); + } + + @Override + public boolean removeMaterialOfInterest(Material material) { + Preconditions.checkArgument(material != null, "material cannot be null"); + + Item item = CraftMagicNumbers.getItem(material); + return getHandle().interestItems.remove(item); + } + + @Override + public Set getInterestList() { + return Collections.unmodifiableSet(getHandle().interestItems.stream().map(CraftMagicNumbers::getMaterial).collect(Collectors.toSet())); + } + + @Override + public Set getBarterList() { + return Collections.unmodifiableSet(getHandle().allowedBarterItems.stream().map(CraftMagicNumbers::getMaterial).collect(Collectors.toSet())); + } + + @Override + public Inventory getInventory() { + return new CraftInventory(getHandle().bu); + } + @Override public EntityPiglin getHandle() { return (EntityPiglin) super.getHandle(); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 43750df524..d6bbee0df0 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -42,6 +42,7 @@ import net.minecraft.world.entity.monster.EntityIllagerWizard; import net.minecraft.world.entity.monster.EntityMonster; import net.minecraft.world.entity.monster.EntitySlime; import net.minecraft.world.entity.monster.EntityStrider; +import net.minecraft.world.entity.monster.piglin.EntityPiglin; import net.minecraft.world.entity.npc.EntityVillager; import net.minecraft.world.entity.npc.NPC; import net.minecraft.world.entity.player.EntityHuman; @@ -109,6 +110,7 @@ import org.bukkit.entity.LightningStrike; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Pig; import org.bukkit.entity.PigZombie; +import org.bukkit.entity.Piglin; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Raider; @@ -178,6 +180,7 @@ import org.bukkit.event.entity.ItemMergeEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.LingeringPotionSplashEvent; import org.bukkit.event.entity.PigZapEvent; +import org.bukkit.event.entity.PiglinBarterEvent; import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerLeashEntityEvent; import org.bukkit.event.entity.PotionSplashEvent; @@ -1599,4 +1602,10 @@ public class CraftEventFactory { return event; } + + public static PiglinBarterEvent callPiglinBarterEvent(EntityPiglin piglin, List outcome, ItemStack input) { + PiglinBarterEvent event = new PiglinBarterEvent((Piglin) piglin.getBukkitEntity(), CraftItemStack.asBukkitCopy(input), outcome.stream().map(CraftItemStack::asBukkitCopy).collect(Collectors.toList())); + Bukkit.getPluginManager().callEvent(event); + return event; + } }