Permit periodic task instead of PlayerMoveEvent through NPCLibOptions

Adds NPCLibOptions as an optional parameter to NPCLib's constructor. The
movement handling specified by the NPCLibOptions will determine whether
to use the PlayerMoveEvent or a task.
This commit is contained in:
A248 2020-04-20 15:16:24 -04:00
parent dfd916dc97
commit b00850b19d
6 changed files with 192 additions and 31 deletions

View File

@ -4,11 +4,14 @@
package net.jitse.npclib;
import net.jitse.npclib.NPCLibOptions.MovementHandling;
import net.jitse.npclib.api.NPC;
import net.jitse.npclib.api.utilities.Logger;
import net.jitse.npclib.listeners.ChunkListener;
import net.jitse.npclib.listeners.PacketListener;
import net.jitse.npclib.listeners.PeriodicMoveListener;
import net.jitse.npclib.listeners.PlayerListener;
import net.jitse.npclib.listeners.PlayerMoveEventListener;
import net.jitse.npclib.metrics.NPCLibMetrics;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@ -23,7 +26,7 @@ public final class NPCLib {
private double autoHideDistance = 50.0;
public NPCLib(JavaPlugin plugin) {
private NPCLib(JavaPlugin plugin, MovementHandling moveHandling) {
this.plugin = plugin;
this.logger = new Logger("NPCLib");
@ -49,6 +52,12 @@ public final class NPCLib {
pluginManager.registerEvents(new PlayerListener(this), plugin);
pluginManager.registerEvents(new ChunkListener(this), plugin);
if (moveHandling.usePme) {
pluginManager.registerEvents(new PlayerMoveEventListener(), plugin);
} else {
pluginManager.registerEvents(new PeriodicMoveListener(this, moveHandling.updateInterval), plugin);
}
// Boot the according packet listener.
new PacketListener().start(this);
@ -59,6 +68,14 @@ public final class NPCLib {
logger.info("Enabled for Minecraft " + versionName);
}
public NPCLib(JavaPlugin plugin) {
this(plugin, MovementHandling.playerMoveEvent());
}
public NPCLib(JavaPlugin plugin, NPCLibOptions options) {
this(plugin, options.moveHandling);
}
/**
* @return The JavaPlugin instance.
*/

View File

@ -0,0 +1,77 @@
package net.jitse.npclib;
/**
* Mutable preferences for library usage
*
* @author A248
*
*/
public class NPCLibOptions {
MovementHandling moveHandling;
/**
* Creates the default options
*
*/
public NPCLibOptions() {
moveHandling = MovementHandling.playerMoveEvent();
}
/**
* Specifies the motion handling which will be used for the library. <br>
* Programmers may choose between using the PlayerMoveEvent or
* a periodic task. <br>
* <br>
* Note that NPCLib will always use events such as the PlayerTeleportEvent
* and PlayerChangedWorldEvent in addition to the specified option.
*
* @param moveHandling the movement handling
* @return the same NPCLibOptions
*/
public NPCLibOptions setMovementHandling(MovementHandling moveHandling) {
this.moveHandling = moveHandling;
return this;
}
/**
* Options relating to movement handling
*
* @author A248
*
*/
public static class MovementHandling {
final boolean usePme;
final long updateInterval;
private MovementHandling(boolean usePme, long updateInterval) {
this.usePme = usePme;
this.updateInterval = updateInterval;
}
/**
* Gets movement handling using the PlayerMoveEvent
*
* @return movement handling
*/
public static MovementHandling playerMoveEvent() {
return new MovementHandling(false, 0);
}
/**
* Gets movement handling using a periodic update interval in ticks.
*
* @param updateInterval the update interval in ticks
* @return movement handling
*/
public static MovementHandling repeatingTask(long updateInterval) {
if (updateInterval <= 0) {
throw new IllegalArgumentException("Negative update interval");
}
return new MovementHandling(true, updateInterval);
}
}
}

View File

@ -0,0 +1,26 @@
package net.jitse.npclib.listeners;
import org.bukkit.entity.Player;
import net.jitse.npclib.internal.NPCBase;
import net.jitse.npclib.internal.NPCManager;
public class HandleMoveBase {
void handleMove(Player player) {
for (NPCBase npc : NPCManager.getAllNPCs()) {
if (!npc.getShown().contains(player.getUniqueId())) {
continue; // NPC was never supposed to be shown to the player.
}
if (!npc.isShown(player) && npc.inRangeOf(player) && npc.inViewOf(player)) {
// The player is in range and can see the NPC, auto-show it.
npc.show(player, true);
} else if (npc.isShown(player) && !npc.inRangeOf(player)) {
// The player is not in range of the NPC anymore, auto-hide it.
npc.hide(player, true);
}
}
}
}

View File

@ -0,0 +1,48 @@
package net.jitse.npclib.listeners;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitTask;
import net.jitse.npclib.NPCLib;
public class PeriodicMoveListener extends HandleMoveBase implements Listener {
private final NPCLib instance;
private final long updateInterval;
private final HashMap<UUID, BukkitTask> tasks = new HashMap<>();
public PeriodicMoveListener(NPCLib instance, long updateInterval) {
this.instance = instance;
this.updateInterval = updateInterval;
}
private void startTask(UUID uuid) {
// purposefully using UUIDs and not holding player references
tasks.put(uuid, Bukkit.getScheduler().runTaskTimer(instance.getPlugin(), () -> {
Player player = Bukkit.getPlayer(uuid);
if (player != null) { // safety check
handleMove(player);
}
}, 1L, updateInterval));
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent evt) {
startTask(evt.getPlayer().getUniqueId());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent evt) {
tasks.remove(evt.getPlayer().getUniqueId()).cancel();
}
}

View File

@ -11,7 +11,6 @@ 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.entity.PlayerDeathEvent;
import org.bukkit.event.player.*;
@ -20,7 +19,7 @@ import org.bukkit.scheduler.BukkitRunnable;
/**
* @author Jitse Boonstra
*/
public class PlayerListener implements Listener {
public class PlayerListener extends HandleMoveBase implements Listener {
private final NPCLib instance;
@ -82,36 +81,8 @@ public class PlayerListener implements Listener {
}
}
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Location from = event.getFrom();
Location to = event.getTo();
// Only check movement when the player moves from one block to another. The event is called often
// as it is also called when the pitch or yaw change. This is worth it from a performance view.
if (to == null || from.getBlockX() != to.getBlockX()
|| from.getBlockY() != to.getBlockY()
|| from.getBlockZ() != to.getBlockZ())
handleMove(event.getPlayer());
}
@EventHandler
public void onPlayerTeleport(PlayerTeleportEvent event) {
handleMove(event.getPlayer());
}
private void handleMove(Player player) {
for (NPCBase npc : NPCManager.getAllNPCs()) {
if (!npc.getShown().contains(player.getUniqueId())) {
continue; // NPC was never supposed to be shown to the player.
}
if (!npc.isShown(player) && npc.inRangeOf(player) && npc.inViewOf(player)) {
// The player is in range and can see the NPC, auto-show it.
npc.show(player, true);
} else if (npc.isShown(player) && !npc.inRangeOf(player)) {
// The player is not in range of the NPC anymore, auto-hide it.
npc.hide(player, true);
}
}
}
}

View File

@ -0,0 +1,22 @@
package net.jitse.npclib.listeners;
import org.bukkit.Location;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class PlayerMoveEventListener extends HandleMoveBase implements Listener {
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
Location from = event.getFrom();
Location to = event.getTo();
// Only check movement when the player moves from one block to another. The event is called often
// as it is also called when the pitch or yaw change. This is worth it from a performance view.
if (to == null || from.getBlockX() != to.getBlockX()
|| from.getBlockY() != to.getBlockY()
|| from.getBlockZ() != to.getBlockZ())
handleMove(event.getPlayer());
}
}