Add listing API for PlayerProfile

This commit is contained in:
Flo0 2024-04-06 23:16:04 +02:00
parent a2035440cf
commit af38fef753
2 changed files with 271 additions and 0 deletions

View File

@ -0,0 +1,121 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Flo0 <flo.roma@web.de>
Date: Sat, 6 Apr 2024 23:15:08 +0200
Subject: [PATCH] Add listing API for PlayerProfile
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
index c6cb4f17469a8f2e60dd3e28d41402851ce5fb21..2c2802caea79f853ec14f0cfe382471d32417b19 100644
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
@@ -54,7 +54,7 @@ import org.jetbrains.annotations.Nullable;
/**
* Represents a player, connected or not
*/
-public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient { // Paper
+public interface Player extends org.bukkit.entity.HumanEntity, Conversable, OfflinePlayer, PluginMessageRecipient, net.kyori.adventure.identity.Identified, net.kyori.adventure.bossbar.BossBarViewer, com.destroystokyo.paper.network.NetworkClient { // Paper
// Paper start
@Override
@@ -2054,6 +2054,69 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
boolean listPlayer(@NotNull Player other);
// Paper end
+ // Paper start - Add Listing API for PlayerProfile
+ /**
+ * Lists the {@code profile} in the tablist.
+ * Burden of tracking the profile is on the caller.
+ * Using profiles of online players is an invalid operation.
+ * Use {@link #listPlayer(Player)} instead.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to list.
+ * @param latency The latency of the profile in milliseconds.
+ * @param gameMode The game mode of the profile.
+ * @param displayName The display name of the profile.
+ */
+ void listProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, int latency, GameMode gameMode, @Nullable net.kyori.adventure.text.Component displayName);
+
+ /**
+ * Lists the {@code profile} in the tablist.
+ * Burden of tracking the profile is on the caller.
+ * Using profiles of online players is an invalid operation.
+ * Use {@link #listPlayer(Player)} instead.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to list.
+ */
+ default void listProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile) {
+ listProfile(profile, 0, GameMode.SURVIVAL, null);
+ }
+
+ /**
+ * Updates the latency of the {@code profile} in the tablist.
+ * If the {@code profile} is not listed, this method has no effect.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to update in the tablist.
+ * @param latency The new latency of the profile in milliseconds.
+ */
+ void updateListedProfileLatency(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, int latency);
+
+ /**
+ * Updates the game mode of the {@code profile} in the tablist.
+ * If the {@code profile} is not listed, this method has no effect.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to update in the tablist.
+ * @param gameMode The new game mode of the profile.
+ */
+ void updateListedProfileGameMode(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, GameMode gameMode);
+
+ /**
+ * Updates the display name of the {@code profile} in the tablist.
+ * If the {@code profile} is not listed, this method has no effect.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to update in the tablist.
+ * @param displayName The new display name of the profile.
+ */
+ void updateListedProfileDisplayName(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @Nullable net.kyori.adventure.text.Component displayName);
+
+ /**
+ * Unlists the {@code profile} from the tablist.
+ * Using profiles of online players is an invalid operation.
+ * Use {@link #unlistPlayer(Player)} instead.
+ *
+ * @param profile The {@link com.destroystokyo.paper.profile.PlayerProfile} to de-list.
+ */
+ void unlistProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile);
+ // Paper end - Add Listing API for PlayerProfile
+
/**
* Checks to see if this player is currently flying or not.
*
@@ -3403,18 +3466,18 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
// Paper start - elytra boost API
/**
- * Boost a Player that's {@link #isGliding()} using a {@link Firework}.
+ * Boost a Player that's {@link #isGliding()} using a {@link org.bukkit.entity.Firework}.
* If the creation of the entity is cancelled, no boosting is done.
* This method does not fire {@link com.destroystokyo.paper.event.player.PlayerElytraBoostEvent}.
*
* @param firework The {@link Material#FIREWORK_ROCKET} to boost the player with
- * @return The {@link Firework} boosting the Player or null if the spawning of the entity was cancelled
+ * @return The {@link org.bukkit.entity.Firework} boosting the Player or null if the spawning of the entity was cancelled
* @throws IllegalArgumentException if {@link #isGliding()} is false
* or if the {@code firework} isn't a {@link Material#FIREWORK_ROCKET}
- * @deprecated use {@link HumanEntity#fireworkBoost(ItemStack)} instead. Note that this method <b>does not</b>
+ * @deprecated use {@link org.bukkit.entity.HumanEntity#fireworkBoost(ItemStack)} instead. Note that this method <b>does not</b>
* check if the player is gliding or not.
*/
- default @Nullable Firework boostElytra(final @NotNull ItemStack firework) {
+ default @Nullable org.bukkit.entity.Firework boostElytra(final @NotNull ItemStack firework) {
com.google.common.base.Preconditions.checkState(this.isGliding(), "Player must be gliding");
return this.fireworkBoost(firework);
}
@@ -3459,7 +3522,7 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
// Paper end - custom chat completions API
// Spigot start
- public class Spigot extends Entity.Spigot {
+ public class Spigot extends org.bukkit.entity.Entity.Spigot {
/**
* Gets the connection address of this player, regardless of whether it

View File

@ -0,0 +1,150 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Flo0 <flo.roma@web.de>
Date: Sat, 6 Apr 2024 23:15:24 +0200
Subject: [PATCH] Add listing API for PlayerProfile
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
index 56eddd28429cf42c02d88b8bf79f8b616fa45289..04a7ad0381cfdb9d5ff913f82553ecbc5dfbc78f 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
@@ -68,6 +68,30 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacke
return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, listed));
}
// Paper end - Add Listing API for Player
+ // Paper start - Add Listing API for PlayerProfile
+ public static ClientboundPlayerInfoUpdatePacket addAndList(UUID playerInfoId, int latency, GameType gameMode, @Nullable Component displayName) {
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(
+ ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED,
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY,
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE,
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME
+ );
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, true, latency, gameMode, displayName));
+ }
+ public static ClientboundPlayerInfoUpdatePacket updateLatency(UUID playerInfoId, int latency) {
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY);
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, true, latency, GameType.DEFAULT_MODE, null));
+ }
+ public static ClientboundPlayerInfoUpdatePacket updateGameMode(UUID playerInfoId, GameType gameMode) {
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE);
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, true, 0, gameMode, null));
+ }
+ public static ClientboundPlayerInfoUpdatePacket updateDisplayName(UUID playerInfoId, @Nullable Component displayName) {
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, true, 0, GameType.DEFAULT_MODE, displayName));
+ }
+ // Paper end - Add Listing API for PlayerProfile
public ClientboundPlayerInfoUpdatePacket(FriendlyByteBuf buf) {
this.actions = buf.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class);
@@ -188,6 +212,11 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacke
this(profileId, null, listed, 0, GameType.DEFAULT_MODE, null, null);
}
// Paper end - Add Listing API for Player
+ // Paper start - Add Listing API for PlayerProfile
+ Entry(UUID profileId, boolean listed, int latency, GameType gameMode, @Nullable Component displayName) {
+ this(profileId, null, listed, latency, gameMode, displayName, null);
+ }
+ // Paper end - Add Listing API for PlayerProfile
}
static class EntryBuilder {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 616d2e479d91673695ade0db151a0099b568904f..434cdeb719d6fdeeace2b632297cb63527619372 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -20,6 +20,7 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -148,7 +149,6 @@ import org.bukkit.craftbukkit.map.CraftMapView;
import org.bukkit.craftbukkit.map.RenderData;
import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
-import org.bukkit.craftbukkit.profile.CraftPlayerProfile;
import org.bukkit.craftbukkit.scoreboard.CraftScoreboard;
import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftLocation;
@@ -161,7 +161,6 @@ import org.bukkit.event.player.PlayerExpCooldownChangeEvent;
import org.bukkit.event.player.PlayerHideEntityEvent;
import org.bukkit.event.player.PlayerRegisterChannelEvent;
import org.bukkit.event.player.PlayerShowEntityEvent;
-import org.bukkit.event.player.PlayerSpawnChangeEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerUnregisterChannelEvent;
import org.bukkit.inventory.EquipmentSlot;
@@ -174,7 +173,6 @@ import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.StandardMessenger;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
-import org.bukkit.profile.PlayerProfile;
import org.bukkit.scoreboard.Scoreboard;
import org.jetbrains.annotations.NotNull;
@@ -2190,6 +2188,60 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
// Paper end - Add Listing API for Player
+ // Paper start - Add Listing API for PlayerProfile
+ @Override
+ public void listProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, int latency, GameMode gameMode, @Nullable net.kyori.adventure.text.Component displayName) {
+ Preconditions.checkNotNull(profile, "profile cannot be null");
+ Preconditions.checkArgument(isOfflineProfile(profile), "using the profile of an online player is not allowed");
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(
+ ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER,
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED
+ );
+ UUID profileId = profile.getId();
+ GameType type = GameType.byId(gameMode.getValue());
+ net.minecraft.network.chat.Component name = io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName);
+ ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.addAndList(profileId, latency, type, name);
+ this.getHandle().connection.send(packet);
+ }
+
+ @Override
+ public void updateListedProfileLatency(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, int latency) {
+ Preconditions.checkNotNull(profile, "profile cannot be null");
+ Preconditions.checkArgument(isOfflineProfile(profile), "using the profile of an online player is not allowed");
+ if (this.getHandle().connection == null) return;
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateLatency(profile.getId(), latency));
+ }
+
+ @Override
+ public void updateListedProfileGameMode(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, GameMode gameMode) {
+ Preconditions.checkNotNull(profile, "profile cannot be null");
+ Preconditions.checkArgument(isOfflineProfile(profile), "using the profile of an online player is not allowed");
+ if (this.getHandle().connection == null) return;
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateGameMode(profile.getId(), GameType.byId(gameMode.getValue())));
+ }
+
+ @Override
+ public void updateListedProfileDisplayName(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @Nullable net.kyori.adventure.text.Component displayName) {
+ Preconditions.checkNotNull(profile, "profile cannot be null");
+ Preconditions.checkArgument(isOfflineProfile(profile), "using the profile of an online player is not allowed");
+ if (this.getHandle().connection == null) return;
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateDisplayName(profile.getId(), io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName)));
+ }
+
+ @Override
+ public void unlistProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile) {
+ Preconditions.checkNotNull(profile, "profile cannot be null");
+ Preconditions.checkArgument(isOfflineProfile(profile), "using the profile of an online player is not allowed");
+ if (this.getHandle().connection == null) return;
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(profile.getId(), false));
+ }
+
+ private boolean isOfflineProfile(@NotNull com.destroystokyo.paper.profile.PlayerProfile profile) {
+ UUID profileId = profile.getId();
+ return Bukkit.getPlayer(profileId) == null;
+ }
+ // Paper end - Add Listing API for PlayerProfile
+
@Override
public Map<String, Object> serialize() {
Map<String, Object> result = new LinkedHashMap<String, Object>();