-
-
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
7232506
commit 00a68b1
Showing
2 changed files
with
222 additions
and
0 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,43 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Corey Shupe <[email protected]> | ||
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. | ||
* |
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,179 @@ | ||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||
From: Corey Shupe <[email protected]> | ||
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>(); |