diff --git a/main/src/main/java/net/citizensnpcs/Metrics.java b/main/src/main/java/net/citizensnpcs/Metrics.java index fc52c1d08..cb5091f08 100644 --- a/main/src/main/java/net/citizensnpcs/Metrics.java +++ b/main/src/main/java/net/citizensnpcs/Metrics.java @@ -40,7 +40,6 @@ import org.bukkit.plugin.java.JavaPlugin; *

* Check out https://bStats.org/ to learn more about bStats! */ -@SuppressWarnings({ "WeakerAccess", "unused" }) public class Metrics { diff --git a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java index cb7c84206..2ce35d26f 100644 --- a/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java +++ b/main/src/main/java/net/citizensnpcs/commands/NPCCommands.java @@ -2519,7 +2519,7 @@ public class NPCCommands { @Command( aliases = { "npc" }, - usage = "rotate (--body [yaw]) (--head [yaw]) (--pitch [pitch]) (-s(mooth))", + usage = "rotate (--towards [x,y,z]) (--body [yaw]) (--head [yaw]) (--pitch [pitch]) (-s(mooth))", desc = "Rotate NPC", flags = "s", modifiers = { "rotate" }, @@ -2527,7 +2527,7 @@ public class NPCCommands { max = 1, permission = "citizens.npc.rotate") public void rotate(CommandContext args, CommandSender sender, NPC npc, @Flag("body") Float yaw, - @Flag("head") Float head, @Flag("pitch") Float pitch) { + @Flag("head") Float head, @Flag("pitch") Float pitch, @Flag("towards") Location towards) { if (args.hasFlag('s')) { if (pitch == null) { pitch = npc.getStoredLocation().getPitch(); @@ -2542,6 +2542,10 @@ public class NPCCommands { npc.getOrAddTrait(RotationTrait.class).getPhysicalSession().rotateToHave(yaw, pitch); return; } + if (towards != null) { + npc.getOrAddTrait(RotationTrait.class).getPhysicalSession().rotateToFace(towards); + return; + } if (yaw != null) { NMS.setBodyYaw(npc.getEntity(), yaw); if (npc.getEntity().getType() == EntityType.PLAYER) { diff --git a/main/src/main/java/net/citizensnpcs/npc/CitizensNPC.java b/main/src/main/java/net/citizensnpcs/npc/CitizensNPC.java index 6a8b84d1f..dc874ba7b 100644 --- a/main/src/main/java/net/citizensnpcs/npc/CitizensNPC.java +++ b/main/src/main/java/net/citizensnpcs/npc/CitizensNPC.java @@ -196,8 +196,7 @@ public class CitizensNPC extends AbstractNPC { @Override public boolean requiresNameHologram() { - return super.requiresNameHologram() - || Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean() && !data().has(NPC.Metadata.HOLOGRAM_FOR); + return super.requiresNameHologram() || Setting.ALWAYS_USE_NAME_HOLOGRAM.asBoolean(); } private void resetCachedCoord() { diff --git a/main/src/main/java/net/citizensnpcs/trait/HologramTrait.java b/main/src/main/java/net/citizensnpcs/trait/HologramTrait.java index d8db1ac01..4ae8ac1c3 100644 --- a/main/src/main/java/net/citizensnpcs/trait/HologramTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/HologramTrait.java @@ -110,10 +110,10 @@ public class HologramTrait extends Trait { hologramNPC = registry.createNPC(EntityType.ARMOR_STAND, line); hologramNPC.getOrAddTrait(ArmorStandTrait.class).setAsHelperEntityWithName(npc); } + hologramNPC.data().set(NPC.Metadata.HOLOGRAM_FOR, npc.getUniqueId().toString()); if (Setting.PACKET_HOLOGRAMS.asBoolean()) { hologramNPC.addTrait(PacketNPC.class); } - hologramNPC.data().set(NPC.Metadata.HOLOGRAM_FOR, npc.getUniqueId().toString()); if (viewRange != -1) { hologramNPC.data().set(NPC.Metadata.TRACKING_RANGE, viewRange); } diff --git a/main/src/main/java/net/citizensnpcs/trait/text/TextBasePrompt.java b/main/src/main/java/net/citizensnpcs/trait/text/TextBasePrompt.java index bbe26b2d9..c358faa00 100644 --- a/main/src/main/java/net/citizensnpcs/trait/text/TextBasePrompt.java +++ b/main/src/main/java/net/citizensnpcs/trait/text/TextBasePrompt.java @@ -28,6 +28,7 @@ public class TextBasePrompt extends StringPrompt { String input = parts[0]; CommandSender sender = (CommandSender) context.getForWhom(); + Messaging.send(sender, getPromptText(context)); if (input.equalsIgnoreCase("add")) { text.add(Joiner.on(' ').join(Arrays.copyOfRange(parts, 1, parts.length))); return this; @@ -59,10 +60,7 @@ public class TextBasePrompt extends StringPrompt { } catch (NumberFormatException e) { Messaging.sendErrorTr(sender, Messages.TEXT_EDITOR_INVALID_PAGE); } - } - Messaging.send(sender, getPromptText(context)); - - if (input.equalsIgnoreCase("delay")) { + } else if (input.equalsIgnoreCase("delay")) { try { int delay = Integer.parseInt(parts[1]); text.setDelay(delay); diff --git a/main/src/main/java/net/citizensnpcs/trait/versioned/BossBarTrait.java b/main/src/main/java/net/citizensnpcs/trait/versioned/BossBarTrait.java index 70b930fbc..b1afe13d3 100644 --- a/main/src/main/java/net/citizensnpcs/trait/versioned/BossBarTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/versioned/BossBarTrait.java @@ -38,7 +38,7 @@ import net.citizensnpcs.util.Util; @TraitName("bossbar") public class BossBarTrait extends Trait { - private BossBar barCache; + private BossBar activeBar; @Persist private BarColor color = BarColor.PURPLE; @Persist @@ -65,11 +65,11 @@ public class BossBarTrait extends Trait { if (npc.isSpawned() && isBoss(npc.getEntity()) && NMS.getBossBar(npc.getEntity()) != null) return (BossBar) NMS.getBossBar(npc.getEntity()); - if (barCache == null) { - barCache = Bukkit.getServer().createBossBar(npc.getFullName(), color, style, + if (activeBar == null) { + activeBar = Bukkit.getServer().createBossBar(npc.getFullName(), color, style, flags.toArray(new BarFlag[flags.size()])); } - return barCache; + return activeBar; } public BarColor getColor() { @@ -114,12 +114,12 @@ public class BossBarTrait extends Trait { @Override public void onDespawn() { - if (barCache == null) + if (activeBar == null) return; - barCache.removeAll(); - barCache.hide(); - barCache = null; + activeBar.removeAll(); + activeBar.hide(); + activeBar = null; } @Override diff --git a/main/src/main/java/net/citizensnpcs/trait/versioned/CamelTrait.java b/main/src/main/java/net/citizensnpcs/trait/versioned/CamelTrait.java index da56e85f2..365ff1ff7 100644 --- a/main/src/main/java/net/citizensnpcs/trait/versioned/CamelTrait.java +++ b/main/src/main/java/net/citizensnpcs/trait/versioned/CamelTrait.java @@ -26,6 +26,10 @@ public class CamelTrait extends Trait { super("cameltrait"); } + public CamelPose getPose() { + return pose; + } + @Override public void run() { if (npc.isSpawned() && npc.getEntity() instanceof Camel) { diff --git a/main/src/main/java/net/citizensnpcs/util/NMS.java b/main/src/main/java/net/citizensnpcs/util/NMS.java index 1d9b6fe6d..082eecb19 100644 --- a/main/src/main/java/net/citizensnpcs/util/NMS.java +++ b/main/src/main/java/net/citizensnpcs/util/NMS.java @@ -145,15 +145,15 @@ public class NMS { BRIDGE.cancelMoveDestination(entity); } + public static Iterable createBundlePacket(List packets) { + return BRIDGE.createBundlePacket(packets); + } + /* * Yggdrasil's default implementation of this method silently fails instead of throwing * an Exception like it should. */ - public static Iterable createBundlePacket(List packets) { - return BRIDGE.createBundlePacket(packets); - } - public static EntityPacketTracker createPacketTracker(Entity entity) { return createPacketTracker(entity, new PacketAggregator()); } @@ -601,6 +601,10 @@ public class NMS { return BRIDGE.getVerticalMovement(bukkitEntity); } + public static Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + return BRIDGE.getViewingPlayers(entity); + } + public static double getWidth(Entity entity) { return BRIDGE.getWidth(entity); } diff --git a/main/src/main/java/net/citizensnpcs/util/NMSBridge.java b/main/src/main/java/net/citizensnpcs/util/NMSBridge.java index 59b679deb..374cd6f3f 100644 --- a/main/src/main/java/net/citizensnpcs/util/NMSBridge.java +++ b/main/src/main/java/net/citizensnpcs/util/NMSBridge.java @@ -116,6 +116,10 @@ public interface NMSBridge { public float getVerticalMovement(Entity entity); + public default Collection getViewingPlayers(Entity entity) { + return ((Player) entity).getTrackedBy(); + } + public double getWidth(Entity entity); public float getYaw(Entity entity); diff --git a/main/src/main/java/net/citizensnpcs/util/PlayerUpdateTask.java b/main/src/main/java/net/citizensnpcs/util/PlayerUpdateTask.java index cde46ce6e..d9524a7db 100644 --- a/main/src/main/java/net/citizensnpcs/util/PlayerUpdateTask.java +++ b/main/src/main/java/net/citizensnpcs/util/PlayerUpdateTask.java @@ -43,6 +43,7 @@ public class PlayerUpdateTask extends BukkitRunnable { PLAYERS.put(entity.getUniqueId(), new PlayerTick((Player) entity)); } } + // convert to sorted list with binary search PLAYERS_PENDING_ADD.clear(); PLAYERS_PENDING_REMOVE.clear(); diff --git a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java index 4d6043ab3..ccbe0bd71 100644 --- a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java +++ b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/NMSImpl.java @@ -702,6 +702,13 @@ public class NMSImpl implements NMSBridge { return handle.bf; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTrackerEntry entry = server.getTracker().trackedEntities.get(entity.getEntityId()); + return PlayerlistTrackerEntry.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return getHandle(entity).width; diff --git a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/PlayerlistTrackerEntry.java b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/PlayerlistTrackerEntry.java index a408d7fff..88b219948 100644 --- a/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/PlayerlistTrackerEntry.java +++ b/v1_10_R1/src/main/java/net/citizensnpcs/nms/v1_10_R1/util/PlayerlistTrackerEntry.java @@ -1,6 +1,8 @@ package net.citizensnpcs.nms.v1_10_R1.util; import java.lang.reflect.Field; +import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; import org.bukkit.entity.EntityType; @@ -96,6 +98,10 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return 0; } + public static Set getSeenBy(EntityTrackerEntry tracker) { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + private static Entity getTracker(EntityTrackerEntry entry) { try { return (Entity) TRACKER.get(entry); diff --git a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java index 3e1c3df8a..04eecfd1d 100644 --- a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java +++ b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/NMSImpl.java @@ -738,6 +738,13 @@ public class NMSImpl implements NMSBridge { return handle.be; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTrackerEntry entry = server.getTracker().trackedEntities.get(entity.getEntityId()); + return PlayerlistTrackerEntry.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return getHandle(entity).width; diff --git a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/PlayerlistTrackerEntry.java b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/PlayerlistTrackerEntry.java index ff6aca35b..7dd6cc567 100644 --- a/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/PlayerlistTrackerEntry.java +++ b/v1_11_R1/src/main/java/net/citizensnpcs/nms/v1_11_R1/util/PlayerlistTrackerEntry.java @@ -4,6 +4,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -12,6 +13,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.npc.ai.NPCHolder; import net.citizensnpcs.util.NMS; @@ -44,6 +46,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -65,6 +77,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -138,6 +160,20 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return 0; } + public static Set getSeenBy(EntityTrackerEntry tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTrackerEntry entry) { try { return (Entity) TRACKER.get(entry); diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java index b83b34363..4c28d01b3 100644 --- a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java +++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/NMSImpl.java @@ -744,6 +744,13 @@ public class NMSImpl implements NMSBridge { return handle.be; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTrackerEntry entry = server.getTracker().trackedEntities.get(entity.getEntityId()); + return PlayerlistTrackerEntry.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/PlayerlistTrackerEntry.java b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/PlayerlistTrackerEntry.java index a10f571c2..b502d84f9 100644 --- a/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/PlayerlistTrackerEntry.java +++ b/v1_12_R1/src/main/java/net/citizensnpcs/nms/v1_12_R1/util/PlayerlistTrackerEntry.java @@ -4,6 +4,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -12,6 +13,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_12_R1.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -45,6 +47,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -66,6 +78,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -147,6 +169,20 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return 0; } + public static Set getSeenBy(EntityTrackerEntry tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTrackerEntry entry) { try { return (Entity) TRACKER.get(entry); diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java index 20ee4eacd..34d82af24 100644 --- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java +++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/NMSImpl.java @@ -767,6 +767,13 @@ public class NMSImpl implements NMSBridge { return handle.bh; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTrackerEntry entry = server.getTracker().trackedEntities.get(entity.getEntityId()); + return PlayerlistTrackerEntry.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerlistTrackerEntry.java b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerlistTrackerEntry.java index 212b09b9d..c585fc100 100644 --- a/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerlistTrackerEntry.java +++ b/v1_13_R2/src/main/java/net/citizensnpcs/nms/v1_13_R2/util/PlayerlistTrackerEntry.java @@ -4,6 +4,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -12,6 +13,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_13_R2.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -45,6 +47,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -66,6 +78,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -146,6 +168,20 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return 0; } + public static Set getSeenBy(EntityTrackerEntry tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTrackerEntry entry) { try { return (Entity) TRACKER.get(entry); diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/NMSImpl.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/NMSImpl.java index 1193e23c0..9ae1eb285 100644 --- a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/NMSImpl.java +++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/NMSImpl.java @@ -818,6 +818,13 @@ public class NMSImpl implements NMSBridge { return handle.bb; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTracker entry = server.getChunkProvider().playerChunkMap.trackedEntities.get(entity.getEntityId()); + return PlayerlistTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/PlayerlistTracker.java b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/PlayerlistTracker.java index 56b3e9475..0729f0089 100644 --- a/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/PlayerlistTracker.java +++ b/v1_14_R1/src/main/java/net/citizensnpcs/nms/v1_14_R1/util/PlayerlistTracker.java @@ -3,6 +3,7 @@ package net.citizensnpcs.nms.v1_14_R1.util; import java.lang.invoke.MethodHandle; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -11,6 +12,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_14_R1.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -46,6 +48,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -67,6 +79,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -133,6 +155,20 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { return false; } + public static Set getSeenBy(EntityTracker tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTracker entry) { try { return (Entity) TRACKER.invoke(entry); diff --git a/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/NMSImpl.java b/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/NMSImpl.java index 4358b95b6..e0ba45b68 100644 --- a/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/NMSImpl.java +++ b/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/NMSImpl.java @@ -833,6 +833,13 @@ public class NMSImpl implements NMSBridge { return handle.aZ; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTracker entry = server.getChunkProvider().playerChunkMap.trackedEntities.get(entity.getEntityId()); + return PlayerlistTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/PlayerlistTracker.java b/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/PlayerlistTracker.java index af6d1dfb9..e16118e4c 100644 --- a/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/PlayerlistTracker.java +++ b/v1_15_R1/src/main/java/net/citizensnpcs/nms/v1_15_R1/util/PlayerlistTracker.java @@ -3,6 +3,7 @@ package net.citizensnpcs.nms.v1_15_R1.util; import java.lang.invoke.MethodHandle; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -11,6 +12,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_15_R1.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -46,6 +48,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -67,6 +79,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -133,6 +155,20 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { return false; } + public static Set getSeenBy(EntityTracker tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTracker entry) { try { return (Entity) TRACKER.invoke(entry); diff --git a/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/NMSImpl.java b/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/NMSImpl.java index d0425cc54..81bf77704 100644 --- a/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/NMSImpl.java +++ b/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/NMSImpl.java @@ -857,6 +857,13 @@ public class NMSImpl implements NMSBridge { return handle.aR; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTracker entry = server.getChunkProvider().playerChunkMap.trackedEntities.get(entity.getEntityId()); + return PlayerlistTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/PlayerlistTracker.java b/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/PlayerlistTracker.java index 75c1db8d1..8910c2cf3 100644 --- a/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/PlayerlistTracker.java +++ b/v1_16_R3/src/main/java/net/citizensnpcs/nms/v1_16_R3/util/PlayerlistTracker.java @@ -3,6 +3,7 @@ package net.citizensnpcs.nms.v1_16_R3.util; import java.lang.invoke.MethodHandle; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -11,6 +12,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_16_R3.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -46,6 +48,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -67,6 +79,16 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -133,6 +155,20 @@ public class PlayerlistTracker extends PlayerChunkMap.EntityTracker { return false; } + public static Set getSeenBy(EntityTracker tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static Entity getTracker(EntityTracker entry) { try { return (Entity) TRACKER.invoke(entry); diff --git a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/entity/EntityHumanNPC.java b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/entity/EntityHumanNPC.java index 7ea3c3b53..e98e9e978 100644 --- a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/entity/EntityHumanNPC.java +++ b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/entity/EntityHumanNPC.java @@ -40,7 +40,6 @@ import net.citizensnpcs.util.Util; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -160,14 +159,6 @@ public class EntityHumanNPC extends ServerPlayer implements NPCHolder, Skinnable } } - @Override - public Packet getAddEntityPacket() { - if (playerlistTracker != null) { - playerlistTracker.updateLastPlayer(); - } - return super.getAddEntityPacket(); - } - @Override public MobAI getAI() { return ai; diff --git a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/NMSImpl.java b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/NMSImpl.java index c47dde816..629baec3b 100644 --- a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/NMSImpl.java +++ b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/NMSImpl.java @@ -860,6 +860,13 @@ public class NMSImpl implements NMSBridge { return handle.xxa; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + ServerLevel server = (ServerLevel) getHandle(entity).level; + TrackedEntity entry = server.getChunkProvider().chunkMap.G.get(entity.getEntityId()); + return PlayerlistTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/PlayerlistTracker.java b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/PlayerlistTracker.java index 272862122..a96719547 100644 --- a/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/PlayerlistTracker.java +++ b/v1_17_R1/src/main/java/net/citizensnpcs/nms/v1_17_R1/util/PlayerlistTracker.java @@ -1,11 +1,17 @@ package net.citizensnpcs.nms.v1_17_R1.util; import java.lang.invoke.MethodHandle; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; +import com.google.common.collect.ForwardingSet; + import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_17_R1.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -15,29 +21,52 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap.TrackedEntity; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.world.entity.Entity; public class PlayerlistTracker extends ChunkMap.TrackedEntity { - private ServerPlayer lastUpdatedPlayer; private final Entity tracker; public PlayerlistTracker(ChunkMap map, Entity entity, int i, int j, boolean flag) { map.super(entity, i, j, flag); this.tracker = entity; + try { + Set set = (Set) TRACKING_SET_GETTER.invoke(this); + TRACKING_SET_SETTER.invoke(this, new ForwardingSet() { + @Override + public boolean add(ServerPlayerConnection conn) { + boolean res = super.add(conn); + if (res) { + Bukkit.getPluginManager().callEvent(new NPCLinkToPlayerEvent(((NPCHolder) tracker).getNPC(), + conn.getPlayer().getBukkitEntity())); + } + return res; + } + + @Override + protected Set delegate() { + return set; + } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent(((NPCHolder) tracker).getNPC(), + ((ServerPlayerConnection) conn).getPlayer().getBukkitEntity())); + } + return removed; + } + }); + } catch (Throwable e) { + e.printStackTrace(); + } } public PlayerlistTracker(ChunkMap map, TrackedEntity entry) { this(map, getTracker(entry), getTrackingDistance(entry), getE(entry), getF(entry)); } - public void updateLastPlayer() { - if (lastUpdatedPlayer != null) { - Bukkit.getPluginManager().callEvent( - new NPCLinkToPlayerEvent(((NPCHolder) tracker).getNPC(), lastUpdatedPlayer.getBukkitEntity())); - lastUpdatedPlayer = null; - } - } - @Override public void updatePlayer(final ServerPlayer entityplayer) { if (entityplayer instanceof EntityHumanNPC) @@ -74,7 +103,6 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { if (cancelled) return; } - this.lastUpdatedPlayer = entityplayer; super.updatePlayer(entityplayer); } @@ -96,6 +124,10 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { return false; } + public static Collection getSeenBy(TrackedEntity tracker) { + return tracker.seenBy.stream().map(c -> c.getPlayer().getBukkitEntity()).collect(Collectors.toSet()); + } + private static Entity getTracker(TrackedEntity entry) { try { return (Entity) TRACKER.invoke(entry); @@ -116,9 +148,11 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e"); private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f"); - private static volatile Boolean REQUIRES_SYNC; + private static volatile Boolean REQUIRES_SYNC = false; private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class); private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class); private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class); private static final MethodHandle TRACKING_RANGE_SETTER = NMS.getFirstFinalSetter(TrackedEntity.class, int.class); + private static final MethodHandle TRACKING_SET_GETTER = NMS.getFirstGetter(TrackedEntity.class, Set.class); + private static final MethodHandle TRACKING_SET_SETTER = NMS.getFirstFinalSetter(TrackedEntity.class, Set.class); } diff --git a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/entity/EntityHumanNPC.java b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/entity/EntityHumanNPC.java index 123c474d3..a74acafd8 100644 --- a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/entity/EntityHumanNPC.java +++ b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/entity/EntityHumanNPC.java @@ -41,7 +41,6 @@ import net.citizensnpcs.util.Util; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; -import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -161,14 +160,6 @@ public class EntityHumanNPC extends ServerPlayer implements NPCHolder, Skinnable } } - @Override - public Packet getAddEntityPacket() { - if (playerlistTracker != null) { - playerlistTracker.updateLastPlayer(); - } - return super.getAddEntityPacket(); - } - @Override public MobAI getAI() { return ai; diff --git a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/NMSImpl.java b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/NMSImpl.java index c87a34346..ee5f3a2eb 100644 --- a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/NMSImpl.java +++ b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/NMSImpl.java @@ -867,6 +867,13 @@ public class NMSImpl implements NMSBridge { return handle.xxa; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + ServerLevel server = (ServerLevel) getHandle(entity).level; + TrackedEntity entry = server.getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); + return PlayerlistTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/PlayerlistTracker.java b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/PlayerlistTracker.java index 69b051e1a..c2ca8315a 100644 --- a/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/PlayerlistTracker.java +++ b/v1_18_R2/src/main/java/net/citizensnpcs/nms/v1_18_R2/util/PlayerlistTracker.java @@ -1,11 +1,17 @@ package net.citizensnpcs.nms.v1_18_R2.util; import java.lang.invoke.MethodHandle; +import java.util.Collection; +import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; +import com.google.common.collect.ForwardingSet; + import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_18_R2.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -15,29 +21,52 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ChunkMap.TrackedEntity; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.world.entity.Entity; public class PlayerlistTracker extends ChunkMap.TrackedEntity { - private ServerPlayer lastUpdatedPlayer; private final Entity tracker; public PlayerlistTracker(ChunkMap map, Entity entity, int i, int j, boolean flag) { map.super(entity, i, j, flag); this.tracker = entity; + try { + Set set = (Set) TRACKING_SET_GETTER.invoke(this); + TRACKING_SET_SETTER.invoke(this, new ForwardingSet() { + @Override + public boolean add(ServerPlayerConnection conn) { + boolean res = super.add(conn); + if (res) { + Bukkit.getPluginManager().callEvent(new NPCLinkToPlayerEvent(((NPCHolder) tracker).getNPC(), + conn.getPlayer().getBukkitEntity())); + } + return res; + } + + @Override + protected Set delegate() { + return set; + } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent(((NPCHolder) tracker).getNPC(), + ((ServerPlayerConnection) conn).getPlayer().getBukkitEntity())); + } + return removed; + } + }); + } catch (Throwable e) { + e.printStackTrace(); + } } public PlayerlistTracker(ChunkMap map, TrackedEntity entry) { this(map, getTracker(entry), getTrackingDistance(entry), getE(entry), getF(entry)); } - public void updateLastPlayer() { - if (lastUpdatedPlayer != null) { - Bukkit.getPluginManager().callEvent( - new NPCLinkToPlayerEvent(((NPCHolder) tracker).getNPC(), lastUpdatedPlayer.getBukkitEntity())); - lastUpdatedPlayer = null; - } - } - @Override public void updatePlayer(final ServerPlayer entityplayer) { if (entityplayer instanceof EntityHumanNPC) @@ -74,7 +103,6 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { if (cancelled) return; } - this.lastUpdatedPlayer = entityplayer; super.updatePlayer(entityplayer); } @@ -96,6 +124,10 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { return false; } + public static Collection getSeenBy(TrackedEntity tracker) { + return tracker.seenBy.stream().map(c -> c.getPlayer().getBukkitEntity()).collect(Collectors.toSet()); + } + private static Entity getTracker(TrackedEntity entry) { try { return (Entity) TRACKER.invoke(entry); @@ -116,9 +148,11 @@ public class PlayerlistTracker extends ChunkMap.TrackedEntity { private static final MethodHandle E = NMS.getGetter(ServerEntity.class, "e"); private static final MethodHandle F = NMS.getGetter(ServerEntity.class, "f"); - private static volatile Boolean REQUIRES_SYNC; + private static volatile Boolean REQUIRES_SYNC = false; private static final MethodHandle TRACKER = NMS.getFirstGetter(TrackedEntity.class, Entity.class); private static final MethodHandle TRACKER_ENTRY = NMS.getFirstGetter(TrackedEntity.class, ServerEntity.class); private static final MethodHandle TRACKING_RANGE = NMS.getFirstGetter(TrackedEntity.class, int.class); private static final MethodHandle TRACKING_RANGE_SETTER = NMS.getFirstFinalSetter(TrackedEntity.class, int.class); + private static final MethodHandle TRACKING_SET_GETTER = NMS.getFirstGetter(TrackedEntity.class, Set.class); + private static final MethodHandle TRACKING_SET_SETTER = NMS.getFirstFinalSetter(TrackedEntity.class, Set.class); } diff --git a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/CitizensEntityTracker.java b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/CitizensEntityTracker.java index 2495c982b..d52accc64 100644 --- a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/CitizensEntityTracker.java +++ b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/CitizensEntityTracker.java @@ -1,7 +1,9 @@ package net.citizensnpcs.nms.v1_19_R3.util; import java.lang.invoke.MethodHandle; +import java.util.Collection; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -9,6 +11,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_19_R3.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -44,6 +47,16 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity { protected Set delegate() { return set; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent(((NPCHolder) tracker).getNPC(), + ((ServerPlayerConnection) conn).getPlayer().getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -111,6 +124,10 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity { return false; } + public static Collection getSeenBy(TrackedEntity tracker) { + return tracker.seenBy.stream().map(c -> c.getPlayer().getBukkitEntity()).collect(Collectors.toSet()); + } + private static Entity getTracker(TrackedEntity entry) { try { return (Entity) TRACKER.invoke(entry); diff --git a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/NMSImpl.java b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/NMSImpl.java index 75d3d6d5b..7551f1be2 100644 --- a/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/NMSImpl.java +++ b/v1_19_R3/src/main/java/net/citizensnpcs/nms/v1_19_R3/util/NMSImpl.java @@ -907,6 +907,13 @@ public class NMSImpl implements NMSBridge { return handle.xxa; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + ServerLevel server = (ServerLevel) getHandle(entity).level; + TrackedEntity entry = server.getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); + return CitizensEntityTracker.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return entity.getWidth(); diff --git a/v1_20_R2/src/main/java/net/citizensnpcs/nms/v1_20_R2/util/CitizensEntityTracker.java b/v1_20_R2/src/main/java/net/citizensnpcs/nms/v1_20_R2/util/CitizensEntityTracker.java index 945a179f3..f49ab2e76 100644 --- a/v1_20_R2/src/main/java/net/citizensnpcs/nms/v1_20_R2/util/CitizensEntityTracker.java +++ b/v1_20_R2/src/main/java/net/citizensnpcs/nms/v1_20_R2/util/CitizensEntityTracker.java @@ -1,7 +1,9 @@ package net.citizensnpcs.nms.v1_20_R2.util; import java.lang.invoke.MethodHandle; +import java.util.Collection; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -9,6 +11,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_20_R2.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -44,6 +47,16 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity { protected Set delegate() { return set; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent(((NPCHolder) tracker).getNPC(), + ((ServerPlayerConnection) conn).getPlayer().getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -94,6 +107,10 @@ public class CitizensEntityTracker extends ChunkMap.TrackedEntity { super.updatePlayer(entityplayer); } + public static Collection getSeenBy(TrackedEntity tracker) { + return tracker.seenBy.stream().map(c -> c.getPlayer().getBukkitEntity()).collect(Collectors.toSet()); + } + private static boolean getTrackDelta(TrackedEntity entry) { try { return (boolean) TRACK_DELTA.invoke(TRACKER_ENTRY.invoke(entry)); diff --git a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/NMSImpl.java b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/NMSImpl.java index b85a306b7..276627f31 100644 --- a/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/NMSImpl.java +++ b/v1_8_R3/src/main/java/net/citizensnpcs/nms/v1_8_R3/util/NMSImpl.java @@ -646,6 +646,13 @@ public class NMSImpl implements NMSBridge { return handle.aZ; } + @Override + public Collection getViewingPlayers(org.bukkit.entity.Entity entity) { + WorldServer server = (WorldServer) NMSImpl.getHandle(entity).getWorld(); + EntityTrackerEntry entry = server.getTracker().trackedEntities.get(entity.getEntityId()); + return PlayerlistTrackerEntry.getSeenBy(entry); + } + @Override public double getWidth(org.bukkit.entity.Entity entity) { return getHandle(entity).width; @@ -1787,9 +1794,7 @@ public class NMSImpl implements NMSBridge { private static final Set BAD_CONTROLLER_LOOK = EnumSet.of(EntityType.SILVERFISH, EntityType.ENDERMITE, EntityType.ENDER_DRAGON, EntityType.BAT, EntityType.SLIME, EntityType.MAGMA_CUBE, EntityType.HORSE, EntityType.GHAST); - private static final float DEFAULT_SPEED = 1F; - public static MethodHandle ENDERDRAGON_CHECK_WALLS = NMS.getFirstMethodHandleWithReturnType(EntityEnderDragon.class, true, boolean.class, AxisAlignedBB.class); private static Method ENTITY_ATTACK_A = NMS.getMethod(Entity.class, "a", true, EntityLiving.class, Entity.class); 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 dbefbaade..a1032a8e7 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 @@ -4,6 +4,7 @@ import java.lang.invoke.MethodHandle; import java.lang.reflect.Field; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -12,6 +13,7 @@ import com.google.common.collect.ForwardingSet; import net.citizensnpcs.api.event.NPCLinkToPlayerEvent; import net.citizensnpcs.api.event.NPCSeenByPlayerEvent; +import net.citizensnpcs.api.event.NPCUnlinkFromPlayerEvent; import net.citizensnpcs.api.npc.NPC; import net.citizensnpcs.nms.v1_8_R3.entity.EntityHumanNPC; import net.citizensnpcs.npc.ai.NPCHolder; @@ -43,6 +45,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { } return res; } + + @Override + public Boolean remove(Object conn) { + Boolean removed = super.remove(conn); + if (removed == true) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -64,6 +76,16 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { protected Set delegate() { return delegate; } + + @Override + public boolean remove(Object conn) { + boolean removed = super.remove(conn); + if (removed) { + Bukkit.getPluginManager().callEvent(new NPCUnlinkFromPlayerEvent( + ((NPCHolder) tracker).getNPC(), ((EntityPlayer) conn).getBukkitEntity())); + } + return removed; + } }); } catch (Throwable e) { e.printStackTrace(); @@ -126,6 +148,20 @@ public class PlayerlistTrackerEntry extends EntityTrackerEntry { return 0; } + public static Set getSeenBy(EntityTrackerEntry tracker) { + if (TRACKING_MAP_GETTER != null) { + Map delegate; + try { + delegate = (Map) TRACKING_MAP_GETTER.invoke(tracker); + } catch (Throwable e) { + return null; + } + return delegate.keySet().stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } else { + return tracker.trackedPlayers.stream().map(p -> p.getBukkitEntity()).collect(Collectors.toSet()); + } + } + private static boolean getU(EntityTrackerEntry entry) { try { return (Boolean) U.get(entry);