Paper/patches/server/1004-Fix-silent-equipment-change-for-mobs.patch
Owen 19a620213f
Fix experience & improvements to block events (#8067)
This is a lot but basically adds a method to disable the dropping of experience and drops experience by default.
This way things that require XP to be dropped manually (via modification), they can drop XP themselves when needed but without touching anywhere else that may drop xp.

It should be noted this causes breakNaturally() to now drop experience.
2024-01-04 15:18:59 -05:00

122 lines
6.4 KiB
Diff

From 0000000000000000000000000000000000000000 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
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
index 16d84042e2575418880897c728a99d1b8bbcdd15..5af48151159135b869ec4753bbcf79dd257c1570 100644
--- a/src/main/java/net/minecraft/world/entity/Mob.java
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
@@ -1059,13 +1059,20 @@ public abstract class Mob extends LivingEntity implements Targeting {
@Override
public void setItemSlot(EquipmentSlot slot, ItemStack stack) {
+ // Paper start
+ setItemSlot(slot, stack, false);
+ }
+
+ @Override
+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) {
+ // Paper end
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
break;
case 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
}
}
diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
index 8e9469fec42f7b6a132cf173f6f5a95777a29b3b..b319021b22c5dceba6199ed27814b2dcf47b8d50 100644
--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
@@ -250,8 +250,8 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
// Paper end
@Override
- public void setItemSlot(EquipmentSlot slot, ItemStack stack) {
- super.setItemSlot(slot, stack);
+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper
+ super.setItemSlot(slot, stack, silent); // Paper
if (!this.level().isClientSide) {
this.reassessWeaponGoal();
}
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 6e46124d67b6c25155a9942b04c09f3dc946a249..cdd03a1602cef13d2e62e6a6655ec2929e0d590f 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1900,7 +1900,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Paper end - optimize redstone (Alternate Current)
// Paper start - notify observers even if grow failed
public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final CraftBlockState craftBlockState) {
- if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { // notify observers if the block state is the same and the Y level equals the original y level (for mega trees)
+ // notify observers if the block state is the same and the Y level equals the original y level (for mega trees)
+ // blocks at the same Y level with the same state can be assumed to be saplings which trigger observers regardless of if the
+ // tree grew or not
+ if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) {
this.notifyAndUpdatePhysics(craftBlockState.getPosition(), null, craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getHandle(), craftBlockState.getFlag(), 512);
}
}
diff --git a/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..81947843d1f2f7dc6f59d7b52f327d60b17d0dcc
--- /dev/null
+++ b/src/test/java/io/papermc/paper/entity/EntitySetItemSlotSilentOverrideTest.java
@@ -0,0 +1,51 @@
+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.AbstractTestingBase;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class EntitySetItemSlotSilentOverrideTest extends AbstractTestingBase {
+
+ public static Stream<ClassInfo> parameters() {
+ final List<ClassInfo> 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");
+ }
+}