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); + 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. + // 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; - } + 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 (npc == null) { + // Default player, not doing magic with the packet. + return true; + } - 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; - - 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) {