Skip to content

Commit 5dda8c8

Browse files
Fix entity tracker methods for 1.17 (#1354)
- In 1.17, EntityTrackerEntries use ServerPlayerConnections instead of EntityPlayers as they did before. This caused the updateEntity to silently fail when removing the players from the trackedPlayers collection (of connections). This was resolved by retrieving the connections of the players before removing them from the list on 1.17+. The getEntityTrackers method failed because it could not find any players for the same reason. This was resolved by retrieving the player from the connection before retrieving the Bukkit player from the EntityPlayer object when running on 1.17+. - This fixes #1340
1 parent 4c0c18d commit 5dda8c8

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

src/main/java/com/comphenix/protocol/injector/EntityUtilities.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
2929
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
3030
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
31+
import com.comphenix.protocol.utility.MinecraftFields;
3132
import com.comphenix.protocol.utility.MinecraftReflection;
3233
import com.comphenix.protocol.utility.MinecraftVersion;
3334
import com.comphenix.protocol.wrappers.WrappedIntHashMap;
@@ -67,7 +68,10 @@ public void updateEntity(Entity entity, List<Player> observers) {
6768
Collection<?> trackedPlayers = getTrackedPlayers(entity);
6869
List<Object> nmsPlayers = unwrapBukkit(observers);
6970

70-
trackedPlayers.removeAll(nmsPlayers);
71+
List<Object> removingEntries = MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() ?
72+
getPlayerConnections(nmsPlayers) : nmsPlayers;
73+
74+
trackedPlayers.removeAll(removingEntries);
7175

7276
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
7377

@@ -103,7 +107,9 @@ public List<Player> getEntityTrackers(Entity entity) {
103107

104108
// Wrap every player - we also ensure that the underlying tracker list is immutable
105109
for (Object tracker : trackedPlayers) {
106-
if (MinecraftReflection.isMinecraftPlayer(tracker)) {
110+
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove() && MinecraftReflection.isServerHandler(tracker)) {
111+
result.add(MinecraftReflection.getBukkitPlayerFromConnection(tracker));
112+
} else if (MinecraftReflection.isMinecraftPlayer(tracker)) {
107113
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
108114
}
109115
}
@@ -266,6 +272,12 @@ public Entity getEntityFromID(World world, int entityID) {
266272
}
267273
}
268274

275+
private List<Object> getPlayerConnections(List<Object> nmsPlayers) {
276+
List<Object> connections = new ArrayList<>(nmsPlayers.size());
277+
nmsPlayers.forEach(nmsPlayer -> connections.add(MinecraftFields.getPlayerConnection(nmsPlayer)));
278+
return connections;
279+
}
280+
269281
private List<Object> unwrapBukkit(List<Player> players) {
270282
List<Object> output = Lists.newArrayList();
271283
BukkitUnwrapper unwrapper = new BukkitUnwrapper();

src/main/java/com/comphenix/protocol/utility/MinecraftFields.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@ public class MinecraftFields {
1515
// Cached accessors
1616
private static volatile FieldAccessor CONNECTION_ACCESSOR;
1717
private static volatile FieldAccessor NETWORK_ACCESSOR;
18-
18+
private static volatile FieldAccessor CONNECTION_ENTITY_ACCESSOR;
19+
1920
private MinecraftFields() {
2021
// Not constructable
2122
}
2223

2324
/**
24-
* Retrieve the network mananger associated with a particular player.
25+
* Retrieve the network manager associated with a particular player.
2526
* @param player - the player.
26-
* @return The network manager, or NULL if no network manager has been asssociated yet.
27+
* @return The network manager, or NULL if no network manager has been associated yet.
2728
*/
2829
public static Object getNetworkManager(Player player) {
2930
Object nmsPlayer = BukkitUnwrapper.getInstance().unwrapItem(player);
@@ -50,9 +51,13 @@ public static Object getPlayerConnection(Player player) {
5051
Preconditions.checkNotNull(player, "player cannot be null!");
5152
return getPlayerConnection(BukkitUnwrapper.getInstance().unwrapItem(player));
5253
}
53-
54-
// Retrieve player connection from a native instance
55-
private static Object getPlayerConnection(Object nmsPlayer) {
54+
55+
/**
56+
* Retrieve the PlayerConnection (or NetServerHandler) associated with a player.
57+
* @param nmsPlayer - the NMS player.
58+
* @return The player connection.
59+
*/
60+
public static Object getPlayerConnection(Object nmsPlayer) {
5661
Preconditions.checkNotNull(nmsPlayer, "nmsPlayer cannot be null!");
5762

5863
if (CONNECTION_ACCESSOR == null) {
@@ -61,4 +66,21 @@ private static Object getPlayerConnection(Object nmsPlayer) {
6166
}
6267
return CONNECTION_ACCESSOR.get(nmsPlayer);
6368
}
69+
70+
/**
71+
* Retrieves the EntityPlayer player field from a PlayerConnection.
72+
*
73+
* @param playerConnection The PlayerConnection object from which to retrieve the EntityPlayer field.
74+
* @return The value of the EntityPlayer field in the PlayerConnection.
75+
*/
76+
public static Object getPlayerFromConnection(Object playerConnection) {
77+
Preconditions.checkNotNull(playerConnection, "playerConnection cannot be null!");
78+
79+
if (CONNECTION_ENTITY_ACCESSOR == null) {
80+
Class<?> connectionClass = MinecraftReflection.getPlayerConnectionClass();
81+
Class<?> entityPlayerClass = MinecraftReflection.getEntityPlayerClass();
82+
CONNECTION_ENTITY_ACCESSOR = Accessors.getFieldAccessor(connectionClass, entityPlayerClass, true);
83+
}
84+
return CONNECTION_ENTITY_ACCESSOR.get(playerConnection);
85+
}
6486
}

src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.bukkit.Bukkit;
4242
import org.bukkit.Material;
4343
import org.bukkit.Server;
44+
import org.bukkit.entity.Player;
4445
import org.bukkit.inventory.ItemStack;
4546

4647
import com.comphenix.protocol.PacketType;
@@ -376,6 +377,21 @@ public static Object getBukkitEntity(Object nmsObject) {
376377
}
377378
}
378379

380+
/**
381+
* Retrieve the Bukkit player from a given PlayerConnection.
382+
* @param playerConnection The PlayerConnection.
383+
* @return A bukkit player.
384+
* @throws RuntimeException If we were unable to retrieve the Bukkit player.
385+
*/
386+
public static Player getBukkitPlayerFromConnection(Object playerConnection)
387+
{
388+
try {
389+
return (Player) getBukkitEntity(MinecraftFields.getPlayerFromConnection(playerConnection));
390+
} catch (Exception e) {
391+
throw new IllegalArgumentException("Cannot get Bukkit entity from connection " + playerConnection, e);
392+
}
393+
}
394+
379395
/**
380396
* Determine if a given object can be found within the package net.minecraft.server.
381397
* @param obj - the object to test.

0 commit comments

Comments
 (0)