mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-21 22:57:01 +01:00
Player listing API (#8782)
This commit is contained in:
parent
7232506c22
commit
00a68b1efe
2 changed files with 222 additions and 0 deletions
43
patches/api/0428-Add-Listing-API-for-Player.patch
Normal file
43
patches/api/0428-Add-Listing-API-for-Player.patch
Normal file
|
@ -0,0 +1,43 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Corey Shupe <coreyshupe101@gmail.com>
|
||||
Date: Wed, 11 Jan 2023 16:40:31 -0500
|
||||
Subject: [PATCH] Add Listing API for Player
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
|
||||
index e3a6c9fc63b36663d33c6a1513e7dc1522790d85..f9dd00210c1762a40259f823aeb8d8a5ddc78e3e 100644
|
||||
--- a/src/main/java/org/bukkit/entity/Player.java
|
||||
+++ b/src/main/java/org/bukkit/entity/Player.java
|
||||
@@ -1841,6 +1841,32 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
|
||||
@ApiStatus.Experimental
|
||||
public boolean canSee(@NotNull Entity entity);
|
||||
|
||||
+ // Paper start
|
||||
+ /**
|
||||
+ * Returns whether the {@code other} player is listed for {@code this}.
|
||||
+ *
|
||||
+ * @param other The other {@link Player} to check for listing.
|
||||
+ * @return True if the {@code other} player is listed for {@code this}.
|
||||
+ */
|
||||
+ boolean isListed(@NotNull Player other);
|
||||
+
|
||||
+ /**
|
||||
+ * Unlists the {@code other} player from the tablist.
|
||||
+ *
|
||||
+ * @param other The other {@link Player} to de-list.
|
||||
+ * @return True if the {@code other} player was listed.
|
||||
+ */
|
||||
+ boolean unlistPlayer(@NotNull Player other);
|
||||
+
|
||||
+ /**
|
||||
+ * Lists the {@code other} player.
|
||||
+ *
|
||||
+ * @param other The other {@link Player} to list.
|
||||
+ * @return True if the {@code other} player was not listed.
|
||||
+ */
|
||||
+ boolean listPlayer(@NotNull Player other);
|
||||
+ // Paper end
|
||||
+
|
||||
/**
|
||||
* Checks to see if this player is currently flying or not.
|
||||
*
|
179
patches/server/1014-Add-Listing-API-for-Player.patch
Normal file
179
patches/server/1014-Add-Listing-API-for-Player.patch
Normal file
|
@ -0,0 +1,179 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Corey Shupe <coreyshupe101@gmail.com>
|
||||
Date: Wed, 11 Jan 2023 16:40:39 -0500
|
||||
Subject: [PATCH] Add Listing API for Player
|
||||
|
||||
|
||||
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 4aa8b483841028fbcc43f9ed47730881263e5065..0a233051c75dddeb7a5f4de8de39fe1afce75e4a 100644
|
||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
|
||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
|
||||
@@ -28,12 +28,46 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacke
|
||||
this.actions = EnumSet.of(action);
|
||||
this.entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(player));
|
||||
}
|
||||
+ // Paper start
|
||||
+ public ClientboundPlayerInfoUpdatePacket(EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, List<ClientboundPlayerInfoUpdatePacket.Entry> entries) {
|
||||
+ this.actions = actions;
|
||||
+ this.entries = entries;
|
||||
+ }
|
||||
+
|
||||
+ public ClientboundPlayerInfoUpdatePacket(EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, ClientboundPlayerInfoUpdatePacket.Entry entry) {
|
||||
+ this.actions = actions;
|
||||
+ this.entries = List.of(entry);
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection<ServerPlayer> players) {
|
||||
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
|
||||
return new ClientboundPlayerInfoUpdatePacket(enumSet, players);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection<ServerPlayer> players, ServerPlayer forPlayer) {
|
||||
+ final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
|
||||
+ final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = new java.util.ArrayList<>(players.size());
|
||||
+ final org.bukkit.craftbukkit.entity.CraftPlayer bukkitEntity = forPlayer.getBukkitEntity();
|
||||
+ for (final ServerPlayer player : players) {
|
||||
+ entries.add(new ClientboundPlayerInfoUpdatePacket.Entry(player, bukkitEntity.isListed(player.getBukkitEntity())));
|
||||
+ }
|
||||
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries);
|
||||
+ }
|
||||
+
|
||||
+ public static ClientboundPlayerInfoUpdatePacket createSinglePlayerInitializing(ServerPlayer player, boolean listed) {
|
||||
+ final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
|
||||
+ final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(new Entry(player, listed));
|
||||
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, entries);
|
||||
+ }
|
||||
+
|
||||
+ public static ClientboundPlayerInfoUpdatePacket updateListed(UUID playerInfoId, boolean listed) {
|
||||
+ EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
|
||||
+ return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, listed));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public ClientboundPlayerInfoUpdatePacket(FriendlyByteBuf buf) {
|
||||
this.actions = buf.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class);
|
||||
this.entries = buf.readList((buf2) -> {
|
||||
@@ -142,8 +176,18 @@ public class ClientboundPlayerInfoUpdatePacket implements Packet<ClientGamePacke
|
||||
|
||||
public static record Entry(UUID profileId, GameProfile profile, boolean listed, int latency, GameType gameMode, @Nullable Component displayName, @Nullable RemoteChatSession.Data chatSession) {
|
||||
Entry(ServerPlayer player) {
|
||||
- this(player.getUUID(), player.getGameProfile(), true, player.latency, player.gameMode.getGameModeForPlayer(), player.getTabListDisplayName(), Optionull.map(player.getChatSession(), RemoteChatSession::asData));
|
||||
+ // Paper start - add listed
|
||||
+ this(player, true);
|
||||
+ }
|
||||
+ Entry(ServerPlayer player, boolean listed) {
|
||||
+ this(player.getUUID(), player.getGameProfile(), listed, player.latency, player.gameMode.getGameModeForPlayer(), player.getTabListDisplayName(), Optionull.map(player.getChatSession(), RemoteChatSession::asData));
|
||||
+ // Paper end - add listed
|
||||
+ }
|
||||
+ // Paper start
|
||||
+ Entry(UUID profileId, boolean listed) {
|
||||
+ this(profileId, null, listed, 0, GameType.DEFAULT_MODE, null, null);
|
||||
}
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
static class EntryBuilder {
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 640e9bd618dc8286933318744c2064ede1fd9b5f..f097ec5b4e3ad6b1a7c464a8cff4f8b2568fcf4f 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -351,14 +351,22 @@ public abstract class PlayerList {
|
||||
// CraftBukkit end
|
||||
|
||||
// CraftBukkit start - sendAll above replaced with this loop
|
||||
- ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player));
|
||||
+ ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper
|
||||
|
||||
final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - use single player info update packet
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
|
||||
|
||||
if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) {
|
||||
+ // Paper start
|
||||
+ if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) {
|
||||
+ // Paper end
|
||||
entityplayer1.connection.send(packet);
|
||||
+ // Paper start
|
||||
+ } else {
|
||||
+ entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false));
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
if (entityplayer1 == player || !bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) { // Paper - don't include joining player
|
||||
@@ -369,7 +377,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
// Paper start - use single player info update packet
|
||||
if (!onlinePlayers.isEmpty()) {
|
||||
- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers));
|
||||
+ player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player));
|
||||
}
|
||||
// Paper end
|
||||
player.sentListPacket = true;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index c9e4a2635c421df192f62c0903659347bce677f9..472705e92cef5802f377637d8ea5c8001d7a185c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -182,6 +182,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private final ConversationTracker conversationTracker = new ConversationTracker();
|
||||
private final Set<String> channels = new HashSet<String>();
|
||||
private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new HashMap<>();
|
||||
+ private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper
|
||||
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
||||
private int hash = 0;
|
||||
private double health = 20;
|
||||
@@ -1973,7 +1974,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
otherPlayer.setUUID(uuidOverride);
|
||||
}
|
||||
// Paper end
|
||||
- this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer)));
|
||||
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(otherPlayer), this.getHandle())); // Paper
|
||||
if (original != null) otherPlayer.setUUID(original); // Paper - uuid override
|
||||
}
|
||||
|
||||
@@ -2082,6 +2083,43 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
return (entity != null) ? this.canSee(entity) : false; // If we can't find it, we can't see it
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean isListed(Player other) {
|
||||
+ return !this.unlistedEntities.contains(other.getUniqueId());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean unlistPlayer(@NotNull Player other) {
|
||||
+ Preconditions.checkNotNull(other, "hidden entity cannot be null");
|
||||
+ if (this.getHandle().connection == null) return false;
|
||||
+ if (this.equals(other)) return false;
|
||||
+ if (!this.canSee(other)) return false;
|
||||
+
|
||||
+ if (unlistedEntities.add(other.getUniqueId())) {
|
||||
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), false));
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean listPlayer(@NotNull Player other) {
|
||||
+ Preconditions.checkNotNull(other, "hidden entity cannot be null");
|
||||
+ if (this.getHandle().connection == null) return false;
|
||||
+ if (this.equals(other)) return false;
|
||||
+ if (!this.canSee(other)) throw new IllegalStateException("Player cannot see other player");
|
||||
+
|
||||
+ if (this.unlistedEntities.remove(other.getUniqueId())) {
|
||||
+ this.getHandle().connection.send(ClientboundPlayerInfoUpdatePacket.updateListed(other.getUniqueId(), true));
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
Loading…
Reference in a new issue