-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
41bc31b
commit e17eb6b
Showing
3 changed files
with
294 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Jake Potrebic <[email protected]> | ||
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Jake Potrebic <[email protected]> | ||
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)); | ||
+ } | ||
+ } | ||
+} |