mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-30 04:02:50 +01:00
ad9c58e103
Since 1.21.2, vanilla split relative teleportation flags into position and delta/velocity flags into separate enum entries. This highlighted a design flaw in the paper api addition for teleport flags, which just simply mirrored internals while also only being able to apply the delta/velocity part of a flag, given the teleport target is always absolute in the API. This patch proposes to simply no longer expose the non-velocity related flags to the API, instead marking the entire Relative enum as being purely velocity related, as non-velocity related flags are not useful to callers. This was done over simply exposing all internal flags, as another vanilla change to the internal enum would result in the same breakage. The newly proposed API *only* promises that the passed flags prevent the loss of velocity in the specific axis/context, which should be independent enough of vanillas specific implementation of this feature.
154 lines
6.9 KiB
Diff
154 lines
6.9 KiB
Diff
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 b0e49ad831f1ebc6b126bf82c5fddaebffb91312..179886dcbda29c5cdb7dbd43e44951ae38d9df96 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
@@ -1300,4 +1300,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 766c1e80997d1bed99f4ebf9499eec60bf70a536..f668359f2fbe765c68fb575c31444bc0404cba0f 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
|
@@ -1294,6 +1294,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;
|
|
}
|
|
@@ -1303,7 +1308,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
|
|
@@ -3540,4 +3545,14 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
|
public void setSendViewDistance(final int viewDistance) {
|
|
throw new UnsupportedOperationException("Not implemented yet");
|
|
}
|
|
+
|
|
+ // 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..5e64dfaeba167374dc45c5becfb2e7114657dff6
|
|
--- /dev/null
|
|
+++ b/src/test/java/org/bukkit/EntityEffectTest.java
|
|
@@ -0,0 +1,82 @@
|
|
+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.bukkit.support.environment.Normal;
|
|
+import org.junit.jupiter.api.Test;
|
|
+
|
|
+import static org.junit.jupiter.api.Assertions.fail;
|
|
+
|
|
+@Normal
|
|
+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));
|
|
+ }
|
|
+ }
|
|
+}
|