From bf607b1e23f8df4d036d6ee0401ae4fcfcc1681e Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:32:48 +0200 Subject: [PATCH] Fix silent equipment change for mobs --- .../net/minecraft/world/entity/Mob.java.patch | 70 +++++++++++++------ .../monster/AbstractSkeleton.java.patch | 10 ++- .../EntitySetItemSlotSilentOverrideTest.java | 52 ++++++++++++++ 3 files changed, 106 insertions(+), 26 deletions(-) create mode 100644 paper-server/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch index 65c5511310..945d862f95 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -35,13 +35,12 @@ protected Mob(EntityType type, Level world) { super(type, world); this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -157,8 +171,14 @@ - if (world instanceof ServerLevel) { +@@ -158,7 +172,13 @@ this.registerGoals(); } -+ -+ } ++ } ++ + // CraftBukkit start + public void setPersistenceRequired(boolean persistenceRequired) { + this.persistenceRequired = persistenceRequired; @@ -95,20 +94,19 @@ } @Override -@@ -397,7 +448,13 @@ - @Nullable - protected SoundEvent getAmbientSound() { +@@ -399,6 +450,12 @@ return null; -+ } -+ + } + + // CraftBukkit start - Add delegate method + public SoundEvent getAmbientSound0() { + return this.getAmbientSound(); - } ++ } + // CraftBukkit end - ++ @Override public void addAdditionalSaveData(CompoundTag nbt) { + super.addAdditionalSaveData(nbt); @@ -473,13 +530,25 @@ nbt.putBoolean("NoAI", this.isNoAi()); } @@ -282,21 +280,47 @@ ProfilerFiller gameprofilerfiller = Profiler.get(); gameprofilerfiller.push("sensing"); -@@ -1009,7 +1115,13 @@ - this.onEquipItem(slot, itemstack1, stack); - } +@@ -994,23 +1100,36 @@ + @Override + public void setItemSlot(EquipmentSlot slot, ItemStack stack) { ++ // Paper start - Fix silent equipment change ++ setItemSlot(slot, stack, false); + } + ++ @Override ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { ++ // Paper end - Fix silent equipment change + this.verifyEquippedItem(stack); + switch (slot.getType()) { + case HAND: +- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case HUMANOID_ARMOR: +- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case ANIMAL_ARMOR: + ItemStack itemstack1 = this.bodyArmorItem; + + this.bodyArmorItem = stack; +- this.onEquipItem(slot, itemstack1, stack); ++ this.onEquipItem(slot, itemstack1, stack, silent); // Paper - Fix silent equipment change + } + + } + + // Paper start + protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox) + return false; - } ++ } + // Paper end - ++ @Override protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { -@@ -1018,6 +1130,7 @@ + super.dropCustomDeathLoot(world, source, causedByPlayer); +@@ -1018,6 +1137,7 @@ while (iterator.hasNext()) { EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next(); @@ -304,7 +328,7 @@ ItemStack itemstack = this.getItemBySlot(enumitemslot); float f = this.getEquipmentDropChance(enumitemslot); -@@ -1042,7 +1155,13 @@ +@@ -1042,7 +1162,13 @@ } this.spawnAtLocation(world, itemstack); @@ -318,7 +342,7 @@ } } } -@@ -1338,7 +1457,7 @@ +@@ -1338,7 +1464,7 @@ if (itemstack.getItem() instanceof SpawnEggItem) { if (this.level() instanceof ServerLevel) { SpawnEggItem itemmonsteregg = (SpawnEggItem) itemstack.getItem(); @@ -327,7 +351,7 @@ optional.ifPresent((entityinsentient) -> { this.onOffspringSpawnedFromEgg(player, entityinsentient); -@@ -1389,28 +1508,51 @@ +@@ -1389,28 +1515,51 @@ return this.restrictRadius != -1.0F; } @@ -385,7 +409,7 @@ } return t0; -@@ -1420,10 +1562,22 @@ +@@ -1420,10 +1569,22 @@ @Nullable public T convertTo(EntityType entityType, ConversionParams context, ConversionParams.AfterConversion finalizer) { @@ -409,7 +433,7 @@ @Override public Leashable.LeashData getLeashData() { return this.leashData; -@@ -1458,7 +1612,15 @@ +@@ -1458,7 +1619,15 @@ boolean flag1 = super.startRiding(entity, force); if (flag1 && this.isLeashed()) { @@ -426,7 +450,7 @@ } return flag1; -@@ -1542,7 +1704,7 @@ +@@ -1542,7 +1711,7 @@ if (f1 > 0.0F && target instanceof LivingEntity) { entityliving = (LivingEntity) target; diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch index b97430b1f7..d726409faf 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch @@ -45,7 +45,7 @@ } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -233,9 +249,22 @@ +@@ -233,11 +249,24 @@ public void readAdditionalSaveData(CompoundTag nbt) { super.readAdditionalSaveData(nbt); this.reassessWeaponGoal(); @@ -58,6 +58,8 @@ + // Paper start - shouldBurnInDay API @Override +- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { +- super.setItemSlot(slot, stack); + public void addAdditionalSaveData(CompoundTag nbt) { + super.addAdditionalSaveData(nbt); + nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); @@ -65,6 +67,8 @@ + // Paper end - shouldBurnInDay API + + @Override - public void setItemSlot(EquipmentSlot slot, ItemStack stack) { - super.setItemSlot(slot, stack); ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper - Fix silent equipment change ++ super.setItemSlot(slot, stack, silent); // Paper - Fix silent equipment change if (!this.level().isClientSide) { + this.reassessWeaponGoal(); + } diff --git a/paper-server/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java b/paper-server/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java new file mode 100644 index 0000000000..18e0ae8155 --- /dev/null +++ b/paper-server/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java @@ -0,0 +1,52 @@ +package io.papermc.paper.entity; + +import io.github.classgraph.ClassGraph; +import io.github.classgraph.ClassInfo; +import io.github.classgraph.MethodInfo; +import io.github.classgraph.MethodInfoList; +import io.github.classgraph.MethodParameterInfo; +import io.github.classgraph.ScanResult; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.bukkit.support.environment.Normal; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.fail; + +@Normal +public class EntitySetItemSlotSilentOverrideTest { + + public static Stream parameters() { + final List classInfo = new ArrayList<>(); + try (ScanResult scanResult = new ClassGraph() + .enableClassInfo() + .enableMethodInfo() + .whitelistPackages("net.minecraft") + .scan() + ) { + for (final ClassInfo subclass : scanResult.getSubclasses("net.minecraft.world.entity.LivingEntity")) { + final MethodInfoList setItemSlot = subclass.getDeclaredMethodInfo("setItemSlot"); + if (!setItemSlot.isEmpty()) { + classInfo.add(subclass); + } + } + } + return classInfo.stream(); + } + + @ParameterizedTest + @MethodSource("parameters") + public void checkSetItemSlotSilentOverrides(ClassInfo overridesSetItemSlot) { + final MethodInfoList setItemSlot = overridesSetItemSlot.getDeclaredMethodInfo("setItemSlot"); + for (final MethodInfo methodInfo : setItemSlot) { + for (final MethodParameterInfo methodParameterInfo : methodInfo.getParameterInfo()) { + if ("boolean".equals(methodParameterInfo.getTypeDescriptor().toStringWithSimpleNames())) { + return; + } + } + } + fail(overridesSetItemSlot.getName() + " needs to override setItemSlot with the boolean silent parameter as well"); + } +}