diff --git a/api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java b/api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java index 30ee9ce..c233355 100644 --- a/api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java +++ b/api/src/main/java/lol/pyr/znpcsplus/util/NpcLocation.java @@ -4,6 +4,8 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.util.NumberConversions; +import java.util.Objects; + public class NpcLocation { private final double x; private final double y; @@ -65,8 +67,8 @@ public class NpcLocation { private static final double _2PI = 2 * Math.PI; - public Location lookingAt(Location loc) { - return lookingAt(new NpcLocation(loc)).toBukkitLocation(loc.getWorld()); + public NpcLocation lookingAt(Location loc) { + return lookingAt(new NpcLocation(loc)); } public NpcLocation lookingAt(NpcLocation loc) { @@ -88,4 +90,17 @@ public class NpcLocation { return new NpcLocation(this.x, this.y, this.z, yaw, pitch); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NpcLocation that = (NpcLocation) o; + return Double.compare(that.x, x) == 0 && Double.compare(that.y, y) == 0 && Double.compare(that.z, z) == 0 && Float.compare(that.yaw, yaw) == 0 && Float.compare(that.pitch, pitch) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z, yaw, pitch); + } } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java index c1a9754..7f03be8 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/ZNpcsPlus.java @@ -35,7 +35,7 @@ import lol.pyr.znpcsplus.scheduling.SpigotScheduler; import lol.pyr.znpcsplus.scheduling.TaskScheduler; import lol.pyr.znpcsplus.skin.cache.SkinCache; import lol.pyr.znpcsplus.skin.cache.SkinCacheCleanTask; -import lol.pyr.znpcsplus.tasks.NpcVisibilityTask; +import lol.pyr.znpcsplus.tasks.NpcProcessorTask; import lol.pyr.znpcsplus.updater.UpdateChecker; import lol.pyr.znpcsplus.updater.UpdateNotificationListener; import lol.pyr.znpcsplus.user.UserListener; @@ -131,7 +131,7 @@ public class ZNpcsPlus extends JavaPlugin { pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker), this); } - scheduler.runDelayedTimerAsync(new NpcVisibilityTask(npcRegistry, configManager), 60L, 10L); + scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, configManager, propertyRegistry), 60L, 3L); scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200); log(ChatColor.WHITE + " * Loading data..."); diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/config/MainConfig.java b/plugin/src/main/java/lol/pyr/znpcsplus/config/MainConfig.java index 8ab15f9..5699da0 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/config/MainConfig.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/config/MainConfig.java @@ -45,4 +45,9 @@ public interface MainConfig { default boolean autoSaveEnabled() { return autoSaveInterval() != -1; } + + @ConfKey("look-property-distance") + @ConfComments("How far should the look property work from in blocks") + @DefaultDouble(10) + double lookPropertyDistance(); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java index 4ea617d..e164616 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcRegistryImpl.java @@ -56,6 +56,12 @@ public class NpcRegistryImpl implements NpcRegistry { return Collections.unmodifiableCollection(npcMap.values()); } + public Collection getProcessable() { + return Collections.unmodifiableCollection(npcMap.values().stream() + .filter(NpcEntryImpl::isProcessed) + .collect(Collectors.toList())); + } + public Collection getAllModifiable() { return Collections.unmodifiableCollection(npcMap.values().stream() .filter(NpcEntryImpl::isAllowCommandModification) diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java index a31d11f..7a1d8e9 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/npc/NpcTypeImpl.java @@ -74,6 +74,7 @@ public class NpcTypeImpl implements NpcType { allowedProperties.add(propertyRegistry.getByName("fire")); allowedProperties.add(propertyRegistry.getByName("invisible")); allowedProperties.add(propertyRegistry.getByName("silent")); + allowedProperties.add(propertyRegistry.getByName("look")); if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) allowedProperties.add(propertyRegistry.getByName("glow")); } diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java b/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java new file mode 100644 index 0000000..43b4b05 --- /dev/null +++ b/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcProcessorTask.java @@ -0,0 +1,57 @@ +package lol.pyr.znpcsplus.tasks; + +import lol.pyr.znpcsplus.config.ConfigManager; +import lol.pyr.znpcsplus.entity.EntityPropertyImpl; +import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl; +import lol.pyr.znpcsplus.npc.NpcEntryImpl; +import lol.pyr.znpcsplus.npc.NpcImpl; +import lol.pyr.znpcsplus.npc.NpcRegistryImpl; +import lol.pyr.znpcsplus.util.NpcLocation; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.NumberConversions; + +public class NpcProcessorTask extends BukkitRunnable { + private final NpcRegistryImpl npcRegistry; + private final ConfigManager configManager; + private final EntityPropertyRegistryImpl propertyRegistry; + + public NpcProcessorTask(NpcRegistryImpl npcRegistry, ConfigManager configManager, EntityPropertyRegistryImpl propertyRegistry) { + this.npcRegistry = npcRegistry; + this.configManager = configManager; + this.propertyRegistry = propertyRegistry; + } + + public void run() { + double distSq = NumberConversions.square(configManager.getConfig().viewDistance()); + double lookPropertyDistSq = NumberConversions.square(configManager.getConfig().lookPropertyDistance()); + EntityPropertyImpl lookProperty = propertyRegistry.getByName("look", Boolean.class); + for (NpcEntryImpl entry : npcRegistry.getProcessable()) { + NpcImpl npc = entry.getNpc(); + + double closestDist = Double.MAX_VALUE; + Player closest = null; + for (Player player : Bukkit.getOnlinePlayers()) { + if (!player.getWorld().equals(npc.getWorld())) continue; + double distance = player.getLocation().distanceSquared(npc.getBukkitLocation()); + + // visibility + boolean inRange = distance <= distSq; + if (!inRange && npc.isShown(player)) npc.hide(player); + if (inRange) { + if (!npc.isShown(player)) npc.show(player); + if (distance < closestDist) { + closestDist = distance; + closest = player; + } + } + } + // look property + if (closest != null && npc.getProperty(lookProperty) && lookPropertyDistSq >= closestDist) { + NpcLocation expected = npc.getLocation().lookingAt(closest.getLocation()); + if (!expected.equals(npc.getLocation())) npc.setLocation(expected); + } + } + } +} diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcVisibilityTask.java b/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcVisibilityTask.java deleted file mode 100644 index f228616..0000000 --- a/plugin/src/main/java/lol/pyr/znpcsplus/tasks/NpcVisibilityTask.java +++ /dev/null @@ -1,33 +0,0 @@ -package lol.pyr.znpcsplus.tasks; - -import lol.pyr.znpcsplus.config.ConfigManager; -import lol.pyr.znpcsplus.npc.NpcEntryImpl; -import lol.pyr.znpcsplus.npc.NpcImpl; -import lol.pyr.znpcsplus.npc.NpcRegistryImpl; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.NumberConversions; - -public class NpcVisibilityTask extends BukkitRunnable { - private final NpcRegistryImpl npcRegistry; - private final ConfigManager configManager; - - public NpcVisibilityTask(NpcRegistryImpl npcRegistry, ConfigManager configManager) { - this.npcRegistry = npcRegistry; - this.configManager = configManager; - } - - public void run() { - double distSq = NumberConversions.square(configManager.getConfig().viewDistance()); - for (NpcEntryImpl entry : npcRegistry.getAll()) { - if (!entry.isProcessed()) continue; - NpcImpl npc = entry.getNpc(); - for (Player player : Bukkit.getOnlinePlayers()) { - boolean inRange = (player.getWorld() == npc.getWorld() && player.getLocation().distanceSquared(npc.getBukkitLocation()) <= distSq); - if (!inRange && npc.isShown(player)) npc.hide(player); - if (inRange && !npc.isShown(player)) npc.show(player); - } - } - } -}