Skip to content
Merged
47 changes: 47 additions & 0 deletions paper-api/src/main/java/io/papermc/paper/math/Angle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.papermc.paper.math;

import org.jspecify.annotations.NullMarked;

/**
* Represents an angle that can be relative or absolute.
*/
@NullMarked
public sealed interface Angle permits AngleImpl {

/**
* Creates a new absolute angle with the specified value. Absolute
* angles are regardless of the current orientation.
*
* @param degrees the angle value, measured in degrees
* @return a new {@code Angle} instance with the specified value
*/
static Angle absolute(float degrees) {
return new AngleImpl(degrees, false);
}

/**
* Creates a new relative angle with the specified value. Relative
* angles are relative to the current orientation.
*
* @param degrees the angle value, measured in degrees
* @return a new {@code Angle} instance with the specified value
*/
static Angle relative(float degrees) {
return new AngleImpl(degrees, true);
}

/**
* Retrieves the value of the angle, measured in degrees.
*
* @return the angle value in degrees
*/
float degrees();


/**
* Determines whether the angle is relative or absolute.
*
* @return {@code true} if the angle is relative, {@code false} if it is absolute
*/
boolean relative();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.papermc.paper.math;

record AngleImpl(float degrees, boolean relative) implements Angle {
}
13 changes: 13 additions & 0 deletions paper-api/src/main/java/org/bukkit/entity/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.UUID;
import io.papermc.paper.datacomponent.DataComponentView;
import io.papermc.paper.entity.LookAnchor;
import io.papermc.paper.math.Angle;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.event.HoverEventSource;
import net.kyori.adventure.util.TriState;
Expand Down Expand Up @@ -135,9 +136,21 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent
*
* @param yaw the yaw
* @param pitch the pitch
* @see #setRotation(Angle, Angle)
*/
@ApiStatus.Obsolete(since = "26.2")
public void setRotation(float yaw, float pitch);

/**
* Sets the entity's rotation.
* <p>
* Note that if the entity is affected by AI, it may override this rotation.
*
* @param yaw the yaw
* @param pitch the pitch
*/
void setRotation(@NotNull Angle yaw, @NotNull Angle pitch);

// Paper start - Teleport API
/**
* Teleports this entity to the given location.
Expand Down
16 changes: 16 additions & 0 deletions paper-api/src/main/java/org/bukkit/entity/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io.papermc.paper.connection.PlayerGameConnection;
import io.papermc.paper.entity.LookAnchor;
import io.papermc.paper.entity.PlayerGiveResult;
import io.papermc.paper.math.Angle;
import io.papermc.paper.math.Position;
import java.net.InetAddress;
import java.net.InetSocketAddress;
Expand Down Expand Up @@ -3804,9 +3805,24 @@ public int getPing() {
*
* @param yaw the yaw
* @param pitch the pitch
* @see #setRotation(Angle, Angle)
*/
@ApiStatus.Obsolete(since = "26.2")
void setRotation(float yaw, float pitch);

/**
* Set the player's rotation.
* <p>
* Note: When using relative angles, client will add corresponding value
* to its yaw/pitch client side, avoiding jitter while the player
* is actively moving their view, it's different from just send
* new absolute angle with only yaw or pitch addition.
*
* @param yaw the yaw
* @param pitch the pitch
*/
void setRotation(Angle yaw, Angle pitch);

/**
* Causes the player to look towards the given entity.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import io.papermc.paper.math.Angle;
import net.kyori.adventure.pointer.PointersSupplier;
import net.kyori.adventure.util.TriState;
import net.md_5.bungee.api.chat.BaseComponent;
Expand Down Expand Up @@ -277,6 +278,17 @@ public void setRotation(float yaw, float pitch) {
this.getHandle().forceSetRotation(yaw, false, pitch, false);
}

@Override
public void setRotation(Angle yaw, Angle pitch) {
NumberConversions.checkFinite(pitch.degrees(), "pitch not finite");
NumberConversions.checkFinite(yaw.degrees(), "yaw not finite");

float yawValue = Location.normalizeYaw(yaw.degrees());
float pitchValue = Location.normalizePitch(pitch.degrees());

this.getHandle().forceSetRotation(yawValue, yaw.relative(), pitchValue, pitch.relative());
}

@Override
public boolean teleport(Location location) {
return this.teleport(location, TeleportCause.PLUGIN);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import io.papermc.paper.entity.LookAnchor;
import io.papermc.paper.entity.PaperPlayerGiveResult;
import io.papermc.paper.entity.PlayerGiveResult;
import io.papermc.paper.math.Angle;
import io.papermc.paper.math.Position;
import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.shorts.ShortArraySet;
Expand Down Expand Up @@ -1298,6 +1299,13 @@ public void setRotation(float yaw, float pitch) {
super.setRotation(yaw, pitch);
}

@Override
public void setRotation(@NonNull Angle yaw, @NonNull Angle pitch) {
if (this.getHandle().connection == null) return;

super.setRotation(yaw, pitch);
}

@Override
public void lookAt(org.bukkit.entity.@NonNull Entity entity, @NonNull LookAnchor playerAnchor, @NonNull LookAnchor entityAnchor) {
this.getHandle().lookAt(toNmsAnchor(playerAnchor), ((CraftEntity) entity).getHandle(), toNmsAnchor(entityAnchor));
Expand Down
Loading