From d9ca07b195caedb1dc35377d8bf302154cd4a917 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Fri, 20 Sep 2019 14:34:16 -0700 Subject: [PATCH 1/8] Optimize important code, add distance interaction check. --- .../npclib/listeners/PacketListener.java | 60 +++++++++++++++---- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java index 36a6431..a02b737 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java @@ -11,12 +11,11 @@ import net.jitse.npclib.api.events.NPCInteractEvent; import net.jitse.npclib.internal.NPCManager; import net.jitse.npclib.internal.SimpleNPC; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; /** * @author Jitse Boonstra @@ -49,31 +48,66 @@ public class PacketListener { private boolean handleInteractPacket(Player player, Object packet) { if (packetPlayInUseEntityClazz.isInstance(packet)) { - SimpleNPC npc = NPCManager.getAllNPCs().stream().filter( - check -> check.isShown(player) && check.getEntityId() == (int) entityIdField.get(packet)) - .findFirst().orElse(null); + SimpleNPC npc = null; + int packetEntityId = (int) entityIdField.get(packet); + + + // Not using streams here is an intentional choice. + // Packet listeners is one of the few places where it is important to write optimized code. + // Lambdas (And the stream api) create a massive amount of objects, especially if it isn't a static lambda. + // So, we're avoiding them here. + // ~ Kneesnap, 9 / 20 / 2019. + + for (SimpleNPC testNPC : NPCManager.getAllNPCs()) { + if (testNPC.isShown(player) && testNPC.getEntityId() == packetEntityId) { + npc = testNPC; + break; + } + } if (npc == null) { // Default player, not doing magic with the packet. return true; } - if (delay.contains(player.getUniqueId())) { + if (delay.contains(player.getUniqueId())) { // There is an active delay. return false; } NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK") ? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK; - Bukkit.getScheduler().runTask(plugin, () -> - Bukkit.getPluginManager().callEvent(new NPCInteractEvent(player, clickType, npc))); - - UUID uuid = player.getUniqueId(); - delay.add(uuid); - Bukkit.getScheduler().runTask(plugin, () -> delay.remove(uuid)); + delay.add(player.getUniqueId()); + Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this)); return false; } return true; } + + // This would be a non-static lambda, and its usage matters, so we'll make it a full class. + private static final class TaskCallNpcInteractEvent implements Runnable { + private NPCInteractEvent eventToCall; + private PacketListener listener; + + private static Location playerLocation = new Location(null, 0, 0, 0); + + TaskCallNpcInteractEvent(NPCInteractEvent eventToCall, PacketListener listener) { + this.eventToCall = eventToCall; + this.listener = listener; + } + + @Override + public void run() { + Player player = eventToCall.getWhoClicked(); + this.listener.delay.remove(player.getUniqueId()); // Remove the NPC from the interact cooldown. + + if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getLocation().getWorld())) + return; // If the NPC and player are not in the same world, abort! + + double distance = player.getLocation(playerLocation).distanceSquared(eventToCall.getNPC().getLocation()); + if (distance <= 64) // Only handle the interaction if the player is within interaction range. This way, hacked clients can't interact with NPCs that they shouldn't be able to interact with. + Bukkit.getPluginManager().callEvent(this.eventToCall); + } + } } From 0ecc238e6a31a6c69b7db89427dd108d80cc7860 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Sun, 22 Sep 2019 12:09:48 -0700 Subject: [PATCH 2/8] Player move optimization. --- .../main/java/net/jitse/npclib/api/NPC.java | 8 +++ .../net/jitse/npclib/internal/SimpleNPC.java | 6 ++ .../npclib/listeners/PacketListener.java | 65 ++++++++++--------- .../npclib/listeners/PlayerListener.java | 17 +++-- 4 files changed, 59 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/api/NPC.java b/api/src/main/java/net/jitse/npclib/api/NPC.java index 9b4d687..3312cf7 100644 --- a/api/src/main/java/net/jitse/npclib/api/NPC.java +++ b/api/src/main/java/net/jitse/npclib/api/NPC.java @@ -6,6 +6,7 @@ package net.jitse.npclib.api; import net.jitse.npclib.api.skin.Skin; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Player; public interface NPC { @@ -35,6 +36,13 @@ public interface NPC { */ Location getLocation(); + /** + * Get the world the NPC is located in. + * + * @return The world the NPC is located in. + */ + World getWorld(); + /** * Create all necessary packets for the NPC so it can be shown to players. * diff --git a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java index 0049b76..74d0a98 100644 --- a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java +++ b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java @@ -13,6 +13,7 @@ import net.jitse.npclib.api.events.NPCShowEvent; import net.jitse.npclib.api.skin.Skin; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.util.Vector; @@ -104,6 +105,11 @@ public abstract class SimpleNPC implements NPC, PacketHandler { return location; } + @Override + public World getWorld() { + return location != null ? location.getWorld() : null; + } + public int getEntityId() { return entityId; } diff --git a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java index a02b737..6a523af 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java @@ -15,7 +15,10 @@ import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import java.util.*; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -47,42 +50,40 @@ public class PacketListener { } private boolean handleInteractPacket(Player player, Object packet) { - if (packetPlayInUseEntityClazz.isInstance(packet)) { - SimpleNPC npc = null; - int packetEntityId = (int) entityIdField.get(packet); - - - // Not using streams here is an intentional choice. - // Packet listeners is one of the few places where it is important to write optimized code. - // Lambdas (And the stream api) create a massive amount of objects, especially if it isn't a static lambda. - // So, we're avoiding them here. - // ~ Kneesnap, 9 / 20 / 2019. - - for (SimpleNPC testNPC : NPCManager.getAllNPCs()) { - if (testNPC.isShown(player) && testNPC.getEntityId() == packetEntityId) { - npc = testNPC; - break; - } - } - - if (npc == null) { - // Default player, not doing magic with the packet. - return true; - } - - if (delay.contains(player.getUniqueId())) { // There is an active delay. - return false; + if (!packetPlayInUseEntityClazz.isInstance(packet)) + return true; // We aren't handling the packet. + + SimpleNPC npc = null; + int packetEntityId = (int) entityIdField.get(packet); + + // Not using streams here is an intentional choice. + // Packet listeners is one of the few places where it is important to write optimized code. + // Lambdas (And the stream api) create a massive amount of objects, especially if it isn't a static lambda. + // So, we're avoiding them here. + // ~ Kneesnap, 9 / 20 / 2019. + + for (SimpleNPC testNPC : NPCManager.getAllNPCs()) { + if (testNPC.isShown(player) && testNPC.getEntityId() == packetEntityId) { + npc = testNPC; + break; } + } - NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK") - ? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK; + if (npc == null) { + // Default player, not doing magic with the packet. + return true; + } - delay.add(player.getUniqueId()); - Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this)); + if (delay.contains(player.getUniqueId())) { // There is an active delay. return false; } - return true; + NPCInteractEvent.ClickType clickType = actionField.get(packet).toString().equals("ATTACK") + ? NPCInteractEvent.ClickType.LEFT_CLICK : NPCInteractEvent.ClickType.RIGHT_CLICK; + + delay.add(player.getUniqueId()); + Bukkit.getScheduler().runTask(plugin, new TaskCallNpcInteractEvent(new NPCInteractEvent(player, clickType, npc), this)); + return false; } // This would be a non-static lambda, and its usage matters, so we'll make it a full class. @@ -102,7 +103,7 @@ public class PacketListener { Player player = eventToCall.getWhoClicked(); this.listener.delay.remove(player.getUniqueId()); // Remove the NPC from the interact cooldown. - if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getLocation().getWorld())) + if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getWorld())) return; // If the NPC and player are not in the same world, abort! double distance = player.getLocation(playerLocation).distanceSquared(eventToCall.getNPC().getLocation()); diff --git a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java index dcd418b..a3a20cb 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java @@ -8,6 +8,7 @@ import net.jitse.npclib.NPCLib; import net.jitse.npclib.internal.NPCManager; import net.jitse.npclib.internal.SimpleNPC; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -46,7 +47,7 @@ public class PlayerListener implements Listener { // The PlayerTeleportEvent is call, and will handle visibility in the new world. for (SimpleNPC npc : NPCManager.getAllNPCs()) { - if (npc.getLocation().getWorld().equals(from)) { + if (npc.getWorld().equals(from)) { if (!npc.getAutoHidden().contains(player.getUniqueId())) { npc.getAutoHidden().add(player.getUniqueId()); npc.hide(player, true, false); @@ -57,7 +58,12 @@ public class PlayerListener implements Listener { @EventHandler public void onPlayerMove(PlayerMoveEvent event) { - handleMove(event.getPlayer()); + Location from = event.getFrom(); + Location to = event.getTo(); + if (to == null || (from.getBlockX() != to.getBlockX() + || from.getBlockY() != to.getBlockY() + || from.getBlockZ() != to.getBlockZ())) + handleMove(event.getPlayer()); // Verify the player changed which block they are on. Since PlayerMoveEvent is one of the most called events, this is worth it. } @EventHandler @@ -72,7 +78,7 @@ public class PlayerListener implements Listener { continue; // NPC was never supposed to be shown to the player. } - if (!npc.getLocation().getWorld().equals(world)) { + if (!npc.getWorld().equals(world)) { continue; // NPC is not in the same world. } @@ -80,8 +86,9 @@ public class PlayerListener implements Listener { // This will cause issues otherwise (e.g. custom skin disappearing). double hideDistance = instance.getAutoHideDistance(); double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); - boolean inRange = distanceSquared <= (Math.pow(hideDistance, 2)) - && distanceSquared <= (Math.pow(Bukkit.getViewDistance() << 4, 2)); + + int tempRange = Bukkit.getViewDistance() << 4; + boolean inRange = distanceSquared <= (hideDistance * hideDistance) && distanceSquared <= (tempRange * tempRange); // Avoids Math.pow due to how intensive it is. Could make a static utility function for it. if (npc.getAutoHidden().contains(player.getUniqueId())) { // Check if the player and NPC are within the range to sendShowPackets it again. if (inRange) { From 3b62c85e7efeb6ddf52c512d7cd0fdb587306752 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Sun, 22 Sep 2019 12:18:53 -0700 Subject: [PATCH 3/8] Handle if a player was kicked, instead of quitting normally. --- .../npclib/listeners/PlayerListener.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java index a3a20cb..055c2f2 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java @@ -12,11 +12,9 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.*; /** * @author Jitse Boonstra @@ -31,12 +29,18 @@ public class PlayerListener implements Listener { @EventHandler public void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); + onPlayerLeave(event.getPlayer()); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onPlayerKick(PlayerKickEvent event) { + onPlayerLeave(event.getPlayer()); + } + + private void onPlayerLeave(Player player) { for (SimpleNPC npc : NPCManager.getAllNPCs()) { npc.getAutoHidden().remove(player.getUniqueId()); - - // Don't need to use NPC#hide since the entity is not registered in the NMS server. - npc.getShown().remove(player.getUniqueId()); + npc.getShown().remove(player.getUniqueId()); // Don't need to use NPC#hide since the entity is not registered in the NMS server. } } From dfa1d14f0ea6583bda446c033982dd21548bf68b Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Sun, 22 Sep 2019 12:23:09 -0700 Subject: [PATCH 4/8] Avoid unintentionally loading loads of chunks with Location#getChunk --- .../jitse/npclib/listeners/ChunkListener.java | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java b/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java index 10d7902..29ce768 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java @@ -9,12 +9,14 @@ import net.jitse.npclib.internal.NPCManager; import net.jitse.npclib.internal.SimpleNPC; import org.bukkit.Bukkit; import org.bukkit.Chunk; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; +import java.util.Objects; import java.util.UUID; /** @@ -33,20 +35,18 @@ public class ChunkListener implements Listener { Chunk chunk = event.getChunk(); for (SimpleNPC npc : NPCManager.getAllNPCs()) { - Chunk npcChunk = npc.getLocation().getChunk(); - - if (chunk.equals(npcChunk)) { - // Unloaded chunk with NPC in it. Hiding it from all players currently shown to. - - for (UUID uuid : npc.getShown()) { - // Safety check so it doesn't send packets if the NPC has already - // been automatically despawned by the system. - if (npc.getAutoHidden().contains(uuid)) { - continue; - } - - npc.hide(Bukkit.getPlayer(uuid), true, true); + if (!isSameChunk(npc.getLocation(), chunk)) + continue; // We aren't unloading the chunk with the NPC in it. + + // We found an NPC in the chunk being unloaded. Time to hide this NPC from all players. + for (UUID uuid : npc.getShown()) { + // Safety check so it doesn't send packets if the NPC has already + // been automatically despawned by the system. + if (npc.getAutoHidden().contains(uuid)) { + continue; } + + npc.hide(Bukkit.getPlayer(uuid), true, true); } } } @@ -56,33 +56,45 @@ public class ChunkListener implements Listener { Chunk chunk = event.getChunk(); for (SimpleNPC npc : NPCManager.getAllNPCs()) { - Chunk npcChunk = npc.getLocation().getChunk(); - - if (chunk.equals(npcChunk)) { - // Loaded chunk with NPC in it. Showing it to the players again. - - for (UUID uuid : npc.getShown()) { - // Make sure not to respawn a not-hidden NPC. - if (!npc.getAutoHidden().contains(uuid)) { - continue; - } + if (!isSameChunk(npc.getLocation(), chunk)) + continue; // The NPC is not in the loaded chunk. + + // The chunk being loaded has this NPC in it. Showing it to all the players again. + for (UUID uuid : npc.getShown()) { + // Make sure not to respawn a not-hidden NPC. + if (!npc.getAutoHidden().contains(uuid)) { + continue; + } - Player player = Bukkit.getPlayer(uuid); + Player player = Bukkit.getPlayer(uuid); + if (player == null) + continue; // Couldn't find the player, so skip. - if (!npcChunk.getWorld().equals(player.getWorld())) { - continue; // Player and NPC are not in the same world. - } + if (!Objects.equals(npc.getWorld(), player.getWorld())) { + continue; // Player and NPC are not in the same world. + } - double hideDistance = instance.getAutoHideDistance(); - double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); - boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); + double hideDistance = instance.getAutoHideDistance(); + double distanceSquared = player.getLocation().distanceSquared(npc.getLocation()); + boolean inRange = distanceSquared <= (hideDistance * hideDistance) || distanceSquared <= (Bukkit.getViewDistance() << 4); - // Show the NPC (if in range). - if (inRange) { - npc.show(player, true); - } + // Show the NPC (if in range). + if (inRange) { + npc.show(player, true); } } } } + + + private static int getChunkCoordinate(int coordinate) { + return coordinate >> 4; + } + + // Using Location#getChunk will load the chunk, which is a pretty hefty task, so we'll want to avoid it. + // Using Location#getChunk would effectively mean we'd load every chunk an NPC is located in when any chunk is unloaded. + private static boolean isSameChunk(Location loc, Chunk chunk) { + return getChunkCoordinate(loc.getBlockX()) == chunk.getX() + && getChunkCoordinate(loc.getBlockZ()) == chunk.getZ(); + } } From 1c035ba29045f05ba85b614f1d792ff6812631f1 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Mon, 23 Sep 2019 13:33:59 -0700 Subject: [PATCH 5/8] Fix 1.12.X support. --- api/src/main/java/net/jitse/npclib/hologram/Hologram.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/hologram/Hologram.java b/api/src/main/java/net/jitse/npclib/hologram/Hologram.java index ae464a4..bf91b78 100644 --- a/api/src/main/java/net/jitse/npclib/hologram/Hologram.java +++ b/api/src/main/java/net/jitse/npclib/hologram/Hologram.java @@ -87,9 +87,9 @@ public class Hologram { Reflection.getMethod(ENTITY_CLAZZ, "setNoGravity", boolean.class) : Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, "setGravity", boolean.class)); - Reflection.MethodInvoker customNameMethod = (version.isAboveOrEqual(MinecraftVersion.V1_12_R1) ? - Reflection.getMethod(ENTITY_CLAZZ, "setCustomName", CHAT_BASE_COMPONENT_CLAZZ) : - Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, "setCustomName", String.class)); + Reflection.MethodInvoker customNameMethod = (version.isAboveOrEqual(MinecraftVersion.V1_12_R1) + ? Reflection.getMethod(ENTITY_CLAZZ, "setCustomName", version.isAboveOrEqual(MinecraftVersion.V1_13_R1) ? CHAT_BASE_COMPONENT_CLAZZ : String.class) + : Reflection.getMethod(ENTITY_ARMOR_STAND_CLAZZ, "setCustomName", String.class)); Reflection.MethodInvoker customNameVisibilityMethod = (version.isAboveOrEqual(MinecraftVersion.V1_12_R1) ? Reflection.getMethod(ENTITY_CLAZZ, "setCustomNameVisible", boolean.class) : @@ -115,7 +115,7 @@ public class Hologram { SET_LOCATION_METHOD.invoke(entityArmorStand, location.getX(), location.getY(), location.getZ(), 0, 0); } - customNameMethod.invoke(entityArmorStand, version.isAboveOrEqual(MinecraftVersion.V1_12_R1) ? + customNameMethod.invoke(entityArmorStand, version.isAboveOrEqual(MinecraftVersion.V1_13_R1) ? CHAT_COMPONENT_TEXT_CONSTRUCTOR.invoke(line) : line); customNameVisibilityMethod.invoke(entityArmorStand, true); gravityMethod.invoke(entityArmorStand, version.isAboveOrEqual(MinecraftVersion.V1_9_R2)); From bc1c9677ba72fd7ff0dd36ceeef1a729d3c5e2ca Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Mon, 23 Sep 2019 13:59:49 -0700 Subject: [PATCH 6/8] Bug-fix the packet listener. --- .../main/java/net/jitse/npclib/listeners/PacketListener.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java index 6a523af..7f1ce9e 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PacketListener.java @@ -102,8 +102,7 @@ public class PacketListener { public void run() { Player player = eventToCall.getWhoClicked(); this.listener.delay.remove(player.getUniqueId()); // Remove the NPC from the interact cooldown. - - if (!Objects.equals(playerLocation.getWorld(), eventToCall.getNPC().getWorld())) + if (!Objects.equals(player.getWorld(), eventToCall.getNPC().getWorld())) return; // If the NPC and player are not in the same world, abort! double distance = player.getLocation(playerLocation).distanceSquared(eventToCall.getNPC().getLocation()); From 3dd725c91c2bb20ba0593cd8097b26d49b5ff8a7 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Mon, 23 Sep 2019 23:48:10 -0700 Subject: [PATCH 7/8] Fix 1.12 kick bug. (Registering a scoreboard while an old one exists.) --- .../main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java index ee47131..6754757 100755 --- a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java @@ -93,8 +93,8 @@ public class NPC_v1_12_R1 extends SimpleNPC { if (scheduler) { // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); + Bukkit.getScheduler().runTask(instance.getPlugin(), () -> + playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister)); } else { playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); } From bd172a100aa9e2d12a0b8db616837809a26cd6f3 Mon Sep 17 00:00:00 2001 From: Kneesnap Date: Wed, 25 Sep 2019 15:02:37 -0700 Subject: [PATCH 8/8] Fully fix kick bug for all versions. The problem was that if a scoreboard team is sent while it's already registered, the player will disconnect. Since there does not appear to be any downside to never removing the team, we just won't remove the team, and send the team only once. If there are any problems with this in the future, we can implement a smart solution which will be able to handle the packet sending properly. --- .../jitse/npclib/internal/PacketHandler.java | 2 +- .../net/jitse/npclib/internal/SimpleNPC.java | 23 +++++++------- .../jitse/npclib/listeners/ChunkListener.java | 2 +- .../npclib/listeners/PlayerListener.java | 10 +++---- .../npclib/nms/v1_10_R1/NPC_v1_10_R1.java | 29 ++++++++---------- .../npclib/nms/v1_11_R1/NPC_v1_11_R1.java | 29 ++++++++---------- .../npclib/nms/v1_12_R1/NPC_v1_12_R1.java | 30 ++++++++----------- .../npclib/nms/v1_13_R1/NPC_v1_13_R1.java | 30 ++++++++----------- .../npclib/nms/v1_13_R2/NPC_v1_13_R2.java | 29 ++++++++---------- .../npclib/nms/v1_14_R1/NPC_v1_14_R1.java | 29 ++++++++---------- .../jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java | 28 ++++++++--------- .../jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java | 29 ++++++++---------- .../jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java | 29 ++++++++---------- .../jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java | 30 ++++++++----------- .../jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java | 29 ++++++++---------- 15 files changed, 160 insertions(+), 198 deletions(-) diff --git a/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java b/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java index 5257bd4..2c4ea29 100755 --- a/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java +++ b/api/src/main/java/net/jitse/npclib/internal/PacketHandler.java @@ -15,5 +15,5 @@ interface PacketHandler { void sendShowPackets(Player player); - void sendHidePackets(Player player, boolean scheduler); + void sendHidePackets(Player player); } diff --git a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java index 74d0a98..497dc2b 100644 --- a/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java +++ b/api/src/main/java/net/jitse/npclib/internal/SimpleNPC.java @@ -58,20 +58,14 @@ public abstract class SimpleNPC implements NPC, PacketHandler { this.skin = skin; gameProfile.getProperties().get("textures").clear(); - - if (skin != null) { + if (skin != null) gameProfile.getProperties().put("textures", new Property("textures", skin.getValue(), skin.getSignature())); - } return this; } @Override public void destroy() { - destroy(true); - } - - public void destroy(boolean scheduler) { NPCManager.remove(this); // Destroy NPC for every player that is still seeing it. @@ -80,7 +74,7 @@ public abstract class SimpleNPC implements NPC, PacketHandler { continue; } - hide(Bukkit.getPlayer(uuid), true, scheduler); + hide(Bukkit.getPlayer(uuid), true); } } @@ -131,6 +125,11 @@ public abstract class SimpleNPC implements NPC, PacketHandler { return this; } + public void onLogout(Player player) { + getAutoHidden().remove(player.getUniqueId()); + getShown().remove(player.getUniqueId()); // Don't need to use NPC#hide since the entity is not registered in the NMS server. + } + @Override public void show(Player player) { show(player, false); @@ -181,10 +180,10 @@ public abstract class SimpleNPC implements NPC, PacketHandler { @Override public void hide(Player player) { - hide(player, false, true); + hide(player, false); } - public void hide(Player player, boolean auto, boolean scheduler) { + public void hide(Player player, boolean auto) { NPCHideEvent event = new NPCHideEvent(this, player, auto); Bukkit.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) { @@ -192,7 +191,7 @@ public abstract class SimpleNPC implements NPC, PacketHandler { } if (auto) { - sendHidePackets(player, scheduler); + sendHidePackets(player); } else { if (!shown.contains(player.getUniqueId())) { throw new RuntimeException("Cannot call hide method without calling NPC#show."); @@ -202,7 +201,7 @@ public abstract class SimpleNPC implements NPC, PacketHandler { if (player.getWorld().equals(location.getWorld()) && player.getLocation().distance(location) <= instance.getAutoHideDistance()) { - sendHidePackets(player, scheduler); + sendHidePackets(player); } else { autoHidden.remove(player.getUniqueId()); } diff --git a/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java b/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java index 29ce768..ab42b7d 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/ChunkListener.java @@ -46,7 +46,7 @@ public class ChunkListener implements Listener { continue; } - npc.hide(Bukkit.getPlayer(uuid), true, true); + npc.hide(Bukkit.getPlayer(uuid), true); } } } diff --git a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java index 055c2f2..2393124 100755 --- a/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java +++ b/api/src/main/java/net/jitse/npclib/listeners/PlayerListener.java @@ -38,10 +38,8 @@ public class PlayerListener implements Listener { } private void onPlayerLeave(Player player) { - for (SimpleNPC npc : NPCManager.getAllNPCs()) { - npc.getAutoHidden().remove(player.getUniqueId()); - npc.getShown().remove(player.getUniqueId()); // Don't need to use NPC#hide since the entity is not registered in the NMS server. - } + for (SimpleNPC npc : NPCManager.getAllNPCs()) + npc.onLogout(player); } @EventHandler @@ -54,7 +52,7 @@ public class PlayerListener implements Listener { if (npc.getWorld().equals(from)) { if (!npc.getAutoHidden().contains(player.getUniqueId())) { npc.getAutoHidden().add(player.getUniqueId()); - npc.hide(player, true, false); + npc.hide(player, true); } } } @@ -103,7 +101,7 @@ public class PlayerListener implements Listener { // Check if the player and NPC are out of range to sendHidePackets it. if (!inRange) { npc.getAutoHidden().add(player.getUniqueId()); - npc.hide(player, true, true); + npc.hide(player, true); } } } diff --git a/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java index 3438a45..cc1b3df 100755 --- a/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java +++ b/nms/v1_10_R1/src/main/java/net/jitse/npclib/nms/v1_10_R1/NPC_v1_10_R1.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_10_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_10_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_10_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -84,20 +90,11 @@ public class NPC_v1_10_R1 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java index 055de27..31b0472 100755 --- a/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java +++ b/nms/v1_11_R1/src/main/java/net/jitse/npclib/nms/v1_11_R1/NPC_v1_11_R1.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_11_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_11_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_11_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -84,20 +90,11 @@ public class NPC_v1_11_R1 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java index 6754757..eebda05 100755 --- a/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java +++ b/nms/v1_12_R1/src/main/java/net/jitse/npclib/nms/v1_12_R1/NPC_v1_12_R1.java @@ -17,19 +17,22 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra */ public class NPC_v1_12_R1 extends SimpleNPC { - private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_12_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +63,20 @@ public class NPC_v1_12_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -83,20 +88,11 @@ public class NPC_v1_12_R1 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTask(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister)); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/NPC_v1_13_R1.java b/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/NPC_v1_13_R1.java index db05c74..e54bccf 100755 --- a/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/NPC_v1_13_R1.java +++ b/nms/v1_13_R1/src/main/java/net/jitse/npclib/nms/v1_13_R1/NPC_v1_13_R1.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_13_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_13_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_13_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,44 +64,36 @@ public class NPC_v1_13_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); hologram.spawn(player); - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> playerConnection.sendPacket(packetPlayOutPlayerInfoRemove), 50); } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java index 54ac946..ef456e5 100755 --- a/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java +++ b/nms/v1_13_R2/src/main/java/net/jitse/npclib/nms/v1_13_R2/NPC_v1_13_R2.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_13_R2 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_13_R2(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_13_R2 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -84,20 +90,11 @@ public class NPC_v1_13_R2 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/NPC_v1_14_R1.java b/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/NPC_v1_14_R1.java index bb799d6..19125b5 100755 --- a/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/NPC_v1_14_R1.java +++ b/nms/v1_14_R1/src/main/java/net/jitse/npclib/nms/v1_14_R1/NPC_v1_14_R1.java @@ -13,7 +13,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -22,10 +25,11 @@ public class NPC_v1_14_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_14_R1(NPCLib instance, List lines) { super(instance, lines); @@ -56,18 +60,20 @@ public class NPC_v1_14_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -80,20 +86,11 @@ public class NPC_v1_14_R1 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java index 5554652..b60bdd5 100755 --- a/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java +++ b/nms/v1_8_R1/src/main/java/net/jitse/npclib/nms/v1_8_R1/NPC_v1_8_R1.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_8_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_8_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_8_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -83,20 +89,12 @@ public class NPC_v1_8_R1 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java index 94e51ca..8357855 100755 --- a/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java +++ b/nms/v1_8_R2/src/main/java/net/jitse/npclib/nms/v1_8_R2/NPC_v1_8_R2.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R2.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_8_R2 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_8_R2(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_8_R2 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -83,20 +89,11 @@ public class NPC_v1_8_R2 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java index 0b4d990..b7742b6 100755 --- a/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java +++ b/nms/v1_8_R3/src/main/java/net/jitse/npclib/nms/v1_8_R3/NPC_v1_8_R3.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_8_R3 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_8_R3(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_8_R3 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -84,20 +90,11 @@ public class NPC_v1_8_R3 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java index 1bb2f2e..42ea977 100755 --- a/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java +++ b/nms/v1_9_R1/src/main/java/net/jitse/npclib/nms/v1_9_R1/NPC_v1_9_R1.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_9_R1.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_9_R1 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_9_R1(NPCLib instance, List lines) { super(instance, lines); @@ -60,44 +64,36 @@ public class NPC_v1_9_R1 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); hologram.spawn(player); - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> playerConnection.sendPacket(packetPlayOutPlayerInfoRemove), 50); } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } } diff --git a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java index 550af84..e5bd316 100755 --- a/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java +++ b/nms/v1_9_R2/src/main/java/net/jitse/npclib/nms/v1_9_R2/NPC_v1_9_R2.java @@ -17,7 +17,10 @@ import org.bukkit.Bukkit; import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; import org.bukkit.entity.Player; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import java.util.UUID; /** * @author Jitse Boonstra @@ -26,10 +29,11 @@ public class NPC_v1_9_R2 extends SimpleNPC { private Hologram hologram; private PacketPlayOutNamedEntitySpawn packetPlayOutNamedEntitySpawn; - private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister, packetPlayOutScoreboardTeamUnregister; + private PacketPlayOutScoreboardTeam packetPlayOutScoreboardTeamRegister; private PacketPlayOutPlayerInfo packetPlayOutPlayerInfoAdd, packetPlayOutPlayerInfoRemove; private PacketPlayOutEntityHeadRotation packetPlayOutEntityHeadRotation; private PacketPlayOutEntityDestroy packetPlayOutEntityDestroy; + private Set hasTeamRegistered = new HashSet<>(); public NPC_v1_9_R2(NPCLib instance, List lines) { super(instance, lines); @@ -60,18 +64,20 @@ public class NPC_v1_9_R2 extends SimpleNPC { // Packet for destroying the NPC: this.packetPlayOutEntityDestroy = new PacketPlayOutEntityDestroy(entityId); // First packet to send. + } - // Second packet to send is "packetPlayOutPlayerInfoRemove". - - this.packetPlayOutScoreboardTeamUnregister = new PacketPlayOutScoreboardTeamWrapper() - .createUnregisterTeam(name); // Third packet to send. + @Override + public void onLogout(Player player) { + super.onLogout(player); + hasTeamRegistered.remove(player.getUniqueId()); } @Override public void sendShowPackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; - playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); + if (hasTeamRegistered.add(player.getUniqueId())) + playerConnection.sendPacket(packetPlayOutScoreboardTeamRegister); playerConnection.sendPacket(packetPlayOutPlayerInfoAdd); playerConnection.sendPacket(packetPlayOutNamedEntitySpawn); playerConnection.sendPacket(packetPlayOutEntityHeadRotation); @@ -84,20 +90,11 @@ public class NPC_v1_9_R2 extends SimpleNPC { } @Override - public void sendHidePackets(Player player, boolean scheduler) { + public void sendHidePackets(Player player) { PlayerConnection playerConnection = ((CraftPlayer) player).getHandle().playerConnection; playerConnection.sendPacket(packetPlayOutEntityDestroy); playerConnection.sendPacket(packetPlayOutPlayerInfoRemove); - hologram.destroy(player); - - if (scheduler) { - // Sending this a bit later so the player doesn't see the name (for that split second). - Bukkit.getScheduler().runTaskLater(instance.getPlugin(), () -> - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister), 5); - } else { - playerConnection.sendPacket(packetPlayOutScoreboardTeamUnregister); - } } }