mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-28 23:38:25 +01:00
Improve entity effect API (#11444)
This commit is contained in:
parent
41bc31b79b
commit
e17eb6be0c
3 changed files with 294 additions and 3 deletions
140
patches/api/0491-Improve-entity-effect-API.patch
Normal file
140
patches/api/0491-Improve-entity-effect-API.patch
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||||
|
Date: Fri, 27 Sep 2024 17:12:50 -0700
|
||||||
|
Subject: [PATCH] Improve entity effect API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/EntityEffect.java b/src/main/java/org/bukkit/EntityEffect.java
|
||||||
|
index 5341957b10cccd7bce5a7595699b1d90412a01d0..83d623cc824ddeeae7350c9f9a757fcf8e97c9ea 100644
|
||||||
|
--- a/src/main/java/org/bukkit/EntityEffect.java
|
||||||
|
+++ b/src/main/java/org/bukkit/EntityEffect.java
|
||||||
|
@@ -112,11 +112,25 @@ public enum EntityEffect {
|
||||||
|
// 5 - unused
|
||||||
|
/**
|
||||||
|
* The smoke when taming an entity fails.
|
||||||
|
+ * @deprecated use {@link EntityEffect#TAMING_FAILED}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.21") // Paper
|
||||||
|
WOLF_SMOKE(6, Tameable.class),
|
||||||
|
+ // Paper start - rename "wolf" effects
|
||||||
|
+ /**
|
||||||
|
+ * The smoke when taming an entity fails.
|
||||||
|
+ */
|
||||||
|
+ TAMING_FAILED(6, Tameable.class),
|
||||||
|
+ /**
|
||||||
|
+ * The hearts when taming an entity succeeds.
|
||||||
|
+ */
|
||||||
|
+ TAMING_SUCCEEDED(7, Tameable.class),
|
||||||
|
+ // Paper end - rename "wolf" effects
|
||||||
|
/**
|
||||||
|
* The hearts when taming an entity succeeds.
|
||||||
|
+ * @deprecated use {@link EntityEffect#TAMING_SUCCEEDED}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.21") // Paper
|
||||||
|
WOLF_HEARTS(7, Tameable.class),
|
||||||
|
/**
|
||||||
|
* When a wolf shakes (after being wet).
|
||||||
|
@@ -204,7 +218,9 @@ public enum EntityEffect {
|
||||||
|
ARMOR_STAND_HIT(32, ArmorStand.class),
|
||||||
|
/**
|
||||||
|
* Entity hurt by thorns attack.
|
||||||
|
+ * @deprecated in favor of {@link LivingEntity#playHurtAnimation(float)} or {@link Entity#broadcastHurtAnimation(java.util.Collection)}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.19.4", forRemoval = true) // Paper
|
||||||
|
THORNS_HURT(33, LivingEntity.class),
|
||||||
|
/**
|
||||||
|
* Iron golem puts away rose.
|
||||||
|
@@ -216,11 +232,15 @@ public enum EntityEffect {
|
||||||
|
TOTEM_RESURRECT(35, LivingEntity.class),
|
||||||
|
/**
|
||||||
|
* Entity hurt due to drowning damage.
|
||||||
|
+ * @deprecated in favor of {@link LivingEntity#playHurtAnimation(float)} or {@link Entity#broadcastHurtAnimation(java.util.Collection)}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.19.4", forRemoval = true)
|
||||||
|
HURT_DROWN(36, LivingEntity.class),
|
||||||
|
/**
|
||||||
|
* Entity hurt due to explosion damage.
|
||||||
|
+ * @deprecated in favor of {@link LivingEntity#playHurtAnimation(float)} or {@link Entity#broadcastHurtAnimation(java.util.Collection)}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.19.4", forRemoval = true)
|
||||||
|
HURT_EXPLOSION(37, LivingEntity.class),
|
||||||
|
/**
|
||||||
|
* Dolphin has been fed and is locating a structure.
|
||||||
|
@@ -244,11 +264,15 @@ public enum EntityEffect {
|
||||||
|
VILLAGER_SPLASH(42, Villager.class),
|
||||||
|
/**
|
||||||
|
* Player's bad omen effect removed to start or increase raid difficult.
|
||||||
|
+ * @deprecated raid system was overhauled in 1.20.5
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.20.5", forRemoval = true)
|
||||||
|
PLAYER_BAD_OMEN_RAID(43, Player.class),
|
||||||
|
/**
|
||||||
|
* Entity hurt due to berry bush. Prickly!
|
||||||
|
+ * @deprecated in favor of {@link LivingEntity#playHurtAnimation(float)} or {@link Entity#broadcastHurtAnimation(java.util.Collection)}
|
||||||
|
*/
|
||||||
|
+ @Deprecated(since = "1.19.4", forRemoval = true)
|
||||||
|
HURT_BERRY_BUSH(44, LivingEntity.class),
|
||||||
|
/**
|
||||||
|
* Fox chews the food in its mouth
|
||||||
|
@@ -331,7 +355,17 @@ public enum EntityEffect {
|
||||||
|
* Sniffer must have a target and be in {@link Sniffer.State#SEARCHING} or
|
||||||
|
* {@link Sniffer.State#DIGGING}
|
||||||
|
*/
|
||||||
|
- SNIFFER_DIG(63, Sniffer.class);
|
||||||
|
+ SNIFFER_DIG(63, Sniffer.class),
|
||||||
|
+ // Paper start - add missing EntityEffect
|
||||||
|
+ /**
|
||||||
|
+ * Armadillo peeks out of its shell
|
||||||
|
+ */
|
||||||
|
+ ARMADILLO_PEEK(64, org.bukkit.entity.Armadillo.class),
|
||||||
|
+ /**
|
||||||
|
+ * {@link org.bukkit.inventory.EquipmentSlot#BODY} armor piece breaks
|
||||||
|
+ */
|
||||||
|
+ BODY_BREAK(65, LivingEntity.class);
|
||||||
|
+ // Paper end - add missing EntityEffect
|
||||||
|
|
||||||
|
private final byte data;
|
||||||
|
private final Class<? extends Entity> applicable;
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
index 725ef320f929d5e3d141c1ed3246d73a7d741f31..d0ae8a94db20281d3664d74718c65234eb2e5f83 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Entity.java
|
||||||
|
@@ -1159,4 +1159,17 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent
|
||||||
|
*/
|
||||||
|
@NotNull String getScoreboardEntryName();
|
||||||
|
// Paper end - entity scoreboard name
|
||||||
|
+
|
||||||
|
+ // Paper start - broadcast hurt animation
|
||||||
|
+ /**
|
||||||
|
+ * Broadcasts a hurt animation. This fakes incoming damage towards the target entity.
|
||||||
|
+ * <p>
|
||||||
|
+ * The target players cannot include {@code this} player. For self-damage, use
|
||||||
|
+ * {@link Player#sendHurtAnimation(float)}.
|
||||||
|
+ *
|
||||||
|
+ * @param players the players to broadcast to (cannot include {@code this}
|
||||||
|
+ * @throws IllegalArgumentException if {@code this} is contained in {@code players}
|
||||||
|
+ */
|
||||||
|
+ void broadcastHurtAnimation(@NotNull java.util.Collection<Player> players);
|
||||||
|
+ // Paper end - broadcast hurt animation
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
index 7c56182acaf827f4b1a986a61cea8e9960604c98..8086acceacbceb2c5a7228fff005e41a86d37008 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Player.java
|
||||||
|
@@ -3859,4 +3859,16 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
||||||
|
@Override
|
||||||
|
Spigot spigot();
|
||||||
|
// Spigot end
|
||||||
|
+
|
||||||
|
+ // Paper start - entity effect API
|
||||||
|
+ /**
|
||||||
|
+ * Plays an entity effect to this player for the target entity
|
||||||
|
+ * <p>
|
||||||
|
+ * If the effect is not applicable to this class of entity, it will not play.
|
||||||
|
+ *
|
||||||
|
+ * @param effect the entity effect
|
||||||
|
+ * @param target the target entity
|
||||||
|
+ */
|
||||||
|
+ void sendEntityEffect(org.bukkit.@NotNull EntityEffect effect, @NotNull Entity target);
|
||||||
|
+ // Paper end - entity effect API
|
||||||
|
}
|
|
@ -95,10 +95,10 @@ index 62914bde6f6b045e6b3682581899d756d1b272f1..ccd81bc7279a92f78bb882c9443cf9ca
|
||||||
Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect);
|
Preconditions.checkArgument(effect.getData() == null || effect == Effect.ELECTRIC_SPARK, "Wrong kind of data for the %s effect", effect);
|
||||||
diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java
|
diff --git a/src/test/java/org/bukkit/EffectTest.java b/src/test/java/org/bukkit/EffectTest.java
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..eaccc9a154ff2f498d765a2932b6f3edb449f4f7
|
index 0000000000000000000000000000000000000000..3129212415c151aa028995b6e698f81b638e4c35
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/test/java/org/bukkit/EffectTest.java
|
+++ b/src/test/java/org/bukkit/EffectTest.java
|
||||||
@@ -0,0 +1,79 @@
|
@@ -0,0 +1,78 @@
|
||||||
+package org.bukkit;
|
+package org.bukkit;
|
||||||
+
|
+
|
||||||
+import com.google.common.base.Joiner;
|
+import com.google.common.base.Joiner;
|
||||||
|
@ -134,7 +134,6 @@ index 0000000000000000000000000000000000000000..eaccc9a154ff2f498d765a2932b6f3ed
|
||||||
+ return !Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class);
|
+ return !Effect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @SuppressWarnings("deprecation")
|
|
||||||
+ @Test
|
+ @Test
|
||||||
+ public void checkAllApiExists() throws ReflectiveOperationException {
|
+ public void checkAllApiExists() throws ReflectiveOperationException {
|
||||||
+ Map<Integer, Effect> toId = new HashMap<>();
|
+ Map<Integer, Effect> toId = new HashMap<>();
|
||||||
|
|
152
patches/server/1060-Improve-entity-effect-API.patch
Normal file
152
patches/server/1060-Improve-entity-effect-API.patch
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||||
|
Date: Fri, 27 Sep 2024 17:13:16 -0700
|
||||||
|
Subject: [PATCH] Improve entity effect API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
index cd789c235acf740ec29c30b180e7fbe1a140caa9..89c8713d2c2206d1b0d8c0a392c9d13b3e736f0c 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
|
@@ -1299,4 +1299,15 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
|
return this.getHandle().getScoreboardName();
|
||||||
|
}
|
||||||
|
// Paper end - entity scoreboard name
|
||||||
|
+
|
||||||
|
+ // Paper start - broadcast hurt animation
|
||||||
|
+ @Override
|
||||||
|
+ public void broadcastHurtAnimation(java.util.Collection<Player> players) {
|
||||||
|
+ //noinspection SuspiciousMethodCalls
|
||||||
|
+ Preconditions.checkArgument(!players.contains(this), "Cannot broadcast hurt animation to self without a yaw");
|
||||||
|
+ for (final org.bukkit.entity.Player player : players) {
|
||||||
|
+ ((CraftPlayer) player).sendHurtAnimation(0, this);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end - broadcast hurt animation
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
index ad740739437be632fc7fedec488a7d0c49534688..42d7660efe5baa6f796f2a7606686c765b6f2478 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
|
@@ -1277,6 +1277,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendHurtAnimation(float yaw) {
|
||||||
|
+ // Paper start - Add target entity to sendHurtAnimation
|
||||||
|
+ this.sendHurtAnimation(yaw, this);
|
||||||
|
+ }
|
||||||
|
+ public void sendHurtAnimation(float yaw, org.bukkit.entity.Entity target) {
|
||||||
|
+ // Paper end - Add target entity to sendHurtAnimation
|
||||||
|
if (this.getHandle().connection == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@@ -1286,7 +1291,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
* This makes no sense. We'll add 90 to it so that 0 = front, clockwise from there.
|
||||||
|
*/
|
||||||
|
float actualYaw = yaw + 90;
|
||||||
|
- this.getHandle().connection.send(new ClientboundHurtAnimationPacket(this.getEntityId(), actualYaw));
|
||||||
|
+ this.getHandle().connection.send(new ClientboundHurtAnimationPacket(target.getEntityId(), actualYaw)); // Paper - Add target entity to sendHurtAnimation
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@@ -3553,4 +3558,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer)this.getHandle())
|
||||||
|
.moonrise$getViewDistanceHolder().setSendViewDistance(viewDistance);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Paper start - entity effect API
|
||||||
|
+ @Override
|
||||||
|
+ public void sendEntityEffect(final org.bukkit.EntityEffect effect, final org.bukkit.entity.Entity target) {
|
||||||
|
+ if (this.getHandle().connection == null || !effect.isApplicableTo(target)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundEntityEventPacket(((CraftEntity) target).getHandle(), effect.getData()));
|
||||||
|
+ }
|
||||||
|
+ // Paper end - entity effect API
|
||||||
|
}
|
||||||
|
diff --git a/src/test/java/org/bukkit/EntityEffectTest.java b/src/test/java/org/bukkit/EntityEffectTest.java
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..fdd3b443ae0ae16a09134d4a8b3e35905e287154
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/test/java/org/bukkit/EntityEffectTest.java
|
||||||
|
@@ -0,0 +1,80 @@
|
||||||
|
+package org.bukkit;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.Joiner;
|
||||||
|
+import java.lang.reflect.Field;
|
||||||
|
+import java.lang.reflect.Modifier;
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.HashSet;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Set;
|
||||||
|
+import net.minecraft.world.entity.EntityEvent;
|
||||||
|
+import org.junit.jupiter.api.Test;
|
||||||
|
+
|
||||||
|
+import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
+
|
||||||
|
+public class EntityEffectTest {
|
||||||
|
+
|
||||||
|
+ private static List<Byte> collectNmsLevelEvents() throws ReflectiveOperationException {
|
||||||
|
+ final List<Byte> events = new ArrayList<>();
|
||||||
|
+ for (final Field field : EntityEvent.class.getFields()) {
|
||||||
|
+ if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.getType() == byte.class) {
|
||||||
|
+ events.add((byte) field.get(null));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ for (int i = 22; i <= 28; i++) {
|
||||||
|
+ events.remove(Byte.valueOf((byte) i)); // all have existing API (debug info and op level)
|
||||||
|
+ }
|
||||||
|
+ events.remove(Byte.valueOf(EntityEvent.STOP_ATTACKING)); // not used on client anywhere
|
||||||
|
+ events.remove(Byte.valueOf(EntityEvent.USE_ITEM_COMPLETE)); // not suitable for API (complete using item on Player)
|
||||||
|
+ events.remove(Byte.valueOf(EntityEvent.FISHING_ROD_REEL_IN)); // not suitable for API (fishing rod reel in on FishingHook)
|
||||||
|
+ events.add((byte) 0); // handled on Arrow (for some reason it's not in the EntityEvent nms file as a constant)
|
||||||
|
+ return events;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private static boolean isNotDeprecated(EntityEffect effect) throws ReflectiveOperationException {
|
||||||
|
+ return !EntityEffect.class.getDeclaredField(effect.name()).isAnnotationPresent(Deprecated.class);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void checkAllApiExists() throws ReflectiveOperationException {
|
||||||
|
+ Map<Byte, EntityEffect> toId = new HashMap<>();
|
||||||
|
+ for (final EntityEffect effect : EntityEffect.values()) {
|
||||||
|
+ if (isNotDeprecated(effect)) {
|
||||||
|
+ toId.put(effect.getData(), effect);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final Set<Byte> missingEvents = new HashSet<>();
|
||||||
|
+ for (final Byte event : collectNmsLevelEvents()) {
|
||||||
|
+ if (toId.get(event) == null) {
|
||||||
|
+ missingEvents.add(event);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (!missingEvents.isEmpty()) {
|
||||||
|
+ fail("Missing API EntityEffects:\n" + Joiner.on("\n").join(missingEvents));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void checkNoExtraApi() throws ReflectiveOperationException {
|
||||||
|
+ Map<Byte, EntityEffect> toId = new HashMap<>();
|
||||||
|
+ for (final EntityEffect effect : EntityEffect.values()) {
|
||||||
|
+ if (isNotDeprecated(effect)) {
|
||||||
|
+ toId.put(effect.getData(), effect);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final List<Byte> nmsEvents = collectNmsLevelEvents();
|
||||||
|
+ final Set<EntityEffect> extraApiEffects = new HashSet<>();
|
||||||
|
+ for (final Map.Entry<Byte, EntityEffect> entry : toId.entrySet()) {
|
||||||
|
+ if (!nmsEvents.contains(entry.getKey())) {
|
||||||
|
+ extraApiEffects.add(entry.getValue());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (!extraApiEffects.isEmpty()) {
|
||||||
|
+ fail("Extra API EntityEffects:\n" + Joiner.on("\n").join(extraApiEffects));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
Loading…
Reference in a new issue