From 1c4a7431211989dd66f1cf5c79a034fb55e81d20 Mon Sep 17 00:00:00 2001 From: fullwall Date: Fri, 3 Nov 2023 00:06:41 +0800 Subject: [PATCH] Consistent NPCLinkToPlayerEvent handling for 1.8.8 --- .../nms/v1_8_R3/entity/EntityHumanNPC.java | 9 --- .../v1_8_R3/util/PlayerlistTrackerEntry.java | 75 ++++++++++++++++++- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/entity/EntityHumanNPC.java b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/entity/EntityHumanNPC.java index aeefe0eb6..3c17b5fa6 100644 --- a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/entity/EntityHumanNPC.java +++ b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/entity/EntityHumanNPC.java @@ -42,7 +42,6 @@ import net.minecraft.server.v1_8_R3.AxisAlignedBB; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.DamageSource; -import net.minecraft.server.v1_8_R3.DataWatcher; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.EnumProtocolDirection; @@ -193,14 +192,6 @@ public class EntityHumanNPC extends EntityPlayer implements NPCHolder, Skinnable return controllerMove; } - @Override - public DataWatcher getDataWatcher() { - if (trackerEntry != null) { - trackerEntry.updateLastPlayer(); - } - return super.getDataWatcher(); - } - public NavigationAbstract getNavigation() { return navigation; } diff --git a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/PlayerlistTrackerEntry.java b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/PlayerlistTrackerEntry.java index e6566185d..f681ea7dd 100644 --- a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/PlayerlistTrackerEntry.java +++ b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/PlayerlistTrackerEntry.java @@ -1,9 +1,15 @@ package net.citizensnpcs.nms.v1_8_R3.util; +import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; +import java.util.Map; +import java.util.Set; import org.bukkit.Bukkit; +import com.google.common.collect.ForwardingMap; +import com.google.common.collect.ForwardingSet; + import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; import net.citizensnpcs.api.npc.NPC; @@ -15,17 +21,65 @@ import net.minecraft.server.v1_8_R3.EntityPlayer; import net.minecraft.server.v1_8_R3.EntityTrackerEntry; public class PlayerlistTrackerEntry extends EntityTrackerEntry { - private EntityPlayer lastUpdatedPlayer; + private Map trackingMap; public PlayerlistTrackerEntry(Entity entity, int i, int j, boolean flag) { super(entity, i, j, flag); + if (TRACKING_MAP_SETTER != null) { + try { + Map delegate = (Map) TRACKING_MAP_GETTER.invoke(this); + trackingMap = delegate; + TRACKING_MAP_SETTER.invoke(this, new ForwardingMap() { + @Override + protected Map delegate() { + return delegate; + } + + @Override + public Boolean put(EntityPlayer player, Boolean value) { + Boolean res = super.put(player, value); + if (res == null) { + updateLastPlayer(player); + } + return res; + } + }); + } catch (Throwable e) { + e.printStackTrace(); + } + } else { + try { + Set delegate = super.trackedPlayers; + TRACKING_SET_SETTER.invoke(this, new ForwardingSet() { + @Override + public boolean add(EntityPlayer player) { + boolean res = super.add(player); + if (res) { + updateLastPlayer(player); + } + return res; + } + + @Override + protected Set delegate() { + return delegate; + } + }); + } catch (Throwable e) { + e.printStackTrace(); + } + } } public PlayerlistTrackerEntry(EntityTrackerEntry entry) { this(entry.tracker, getB(entry), getC(entry), getU(entry)); } - public void updateLastPlayer() { + private boolean isTracked(EntityPlayer player) { + return trackingMap != null ? trackingMap.containsKey(player) : trackedPlayers.contains(player); + } + + public void updateLastPlayer(EntityPlayer lastUpdatedPlayer) { if (lastUpdatedPlayer != null) { Bukkit.getPluginManager().callEvent( new NPCLinkToPlayerEvent(((NPCHolder) tracker).getNPC(), lastUpdatedPlayer.getBukkitEntity())); @@ -37,7 +91,7 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { public void updatePlayer(final EntityPlayer entityplayer) { if (entityplayer instanceof EntityHumanNPC) return; - if (!trackedPlayers.contains(entityplayer) && tracker instanceof NPCHolder) { + if (!isTracked(entityplayer) && tracker instanceof NPCHolder) { NPC npc = ((NPCHolder) tracker).getNPC(); NPCSeenByPlayerEvent event = new NPCSeenByPlayerEvent(npc, entityplayer.getBukkitEntity()); Bukkit.getPluginManager().callEvent(event); @@ -45,7 +99,6 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return; } - lastUpdatedPlayer = entityplayer; super.updatePlayer(entityplayer); } @@ -88,5 +141,19 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { private static Field B = NMS.getField(EntityTrackerEntry.class, "b"); private static Field C = NMS.getField(EntityTrackerEntry.class, "c"); + private static MethodHandle TRACKING_MAP_GETTER; + private static MethodHandle TRACKING_MAP_SETTER; + private static final MethodHandle TRACKING_SET_SETTER = NMS.getFirstFinalSetter(EntityTrackerEntry.class, + Set.class); private static Field U = NMS.getField(EntityTrackerEntry.class, "u"); + static { + try { + // Old paper versions override the tracked player set to be a map + if (EntityTrackerEntry.class.getField("trackedPlayerMap") != null) { + TRACKING_MAP_SETTER = NMS.getFirstSetter(EntityTrackerEntry.class, Map.class); + TRACKING_MAP_GETTER = NMS.getFirstGetter(EntityTrackerEntry.class, Map.class); + } + } catch (Exception e) { + } + } }