Properly remove wander waypoint marker

This commit is contained in:
fullwall 2020-01-12 00:33:43 +09:00
parent a0e3b23bc3
commit 41f4c6e1b4

View File

@ -32,289 +32,291 @@ import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Util; import net.citizensnpcs.util.Util;
/** /**
* A wandering waypoint provider that wanders between either a box centered at the current location or inside a region * A wandering waypoint provider that wanders between either a box centered at
* defined by a list of boxes. * the current location or inside a region defined by a list of boxes.
*/ */
public class WanderWaypointProvider public class WanderWaypointProvider
implements WaypointProvider, Supplier<PhTreeSolid<Boolean>>, Function<NPC, Location> { implements WaypointProvider, Supplier<PhTreeSolid<Boolean>>, Function<NPC, Location> {
private WanderGoal currentGoal; private WanderGoal currentGoal;
@Persist @Persist
public int delay = -1; public int delay = -1;
private NPC npc; private NPC npc;
private volatile boolean paused; private volatile boolean paused;
@Persist @Persist
private final List<Location> regionCentres = Lists.newArrayList(); private final List<Location> regionCentres = Lists.newArrayList();
private PhTreeSolid<Boolean> tree = PhTreeSolid.create(3); private PhTreeSolid<Boolean> tree = PhTreeSolid.create(3);
@Persist @Persist
public int xrange = DEFAULT_XRANGE; public int xrange = DEFAULT_XRANGE;
@Persist @Persist
public int yrange = DEFAULT_YRANGE; public int yrange = DEFAULT_YRANGE;
public void addRegionCentre(Location centre) { public void addRegionCentre(Location centre) {
regionCentres.add(centre); regionCentres.add(centre);
recalculateTree(); recalculateTree();
} }
public void addRegionCentres(Collection<Location> centre) { public void addRegionCentres(Collection<Location> centre) {
regionCentres.addAll(centre); regionCentres.addAll(centre);
recalculateTree(); recalculateTree();
} }
@Override @Override
public Location apply(NPC npc) { public Location apply(NPC npc) {
Location closestCentre = null; Location closestCentre = null;
double minDist = Double.MAX_VALUE; double minDist = Double.MAX_VALUE;
for (Location centre : regionCentres) { for (Location centre : regionCentres) {
double d = centre.distanceSquared(npc.getStoredLocation()); double d = centre.distanceSquared(npc.getStoredLocation());
if (d < minDist) { if (d < minDist) {
minDist = d; minDist = d;
closestCentre = centre; closestCentre = centre;
} }
} }
if (closestCentre != null) { if (closestCentre != null) {
// TODO: should find closest edge block that is valid // TODO: should find closest edge block that is valid
return MinecraftBlockExaminer.findValidLocation(closestCentre, xrange, yrange); return MinecraftBlockExaminer.findValidLocation(closestCentre, xrange, yrange);
} }
return null; return null;
} }
@Override @Override
public WaypointEditor createEditor(final CommandSender sender, CommandContext args) { public WaypointEditor createEditor(final CommandSender sender, CommandContext args) {
return new WaypointEditor() { return new WaypointEditor() {
boolean editingRegions = false; boolean editingRegions = false;
EntityMarkers<Location> markers = new EntityMarkers<Location>(); EntityMarkers<Location> markers = new EntityMarkers<Location>();
@Override @Override
public void begin() { public void begin() {
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_BEGIN); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_BEGIN);
if (currentGoal != null) { if (currentGoal != null) {
currentGoal.pause(); currentGoal.pause();
} }
} }
@Override @Override
public void end() { public void end() {
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_END); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_END);
editingRegions = false; editingRegions = false;
if (currentGoal != null) { if (currentGoal != null) {
currentGoal.unpause(); currentGoal.unpause();
} }
} }
private String formatLoc(Location location) { private String formatLoc(Location location) {
return String.format("[[%d]], [[%d]], [[%d]]", location.getBlockX(), location.getBlockY(), return String.format("[[%d]], [[%d]], [[%d]]", location.getBlockX(), location.getBlockY(),
location.getBlockZ()); location.getBlockZ());
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onPlayerChat(AsyncPlayerChatEvent event) { public void onPlayerChat(AsyncPlayerChatEvent event) {
if (!event.getPlayer().equals(sender)) if (!event.getPlayer().equals(sender))
return; return;
String message = event.getMessage().toLowerCase(); String message = event.getMessage().toLowerCase();
if (message.startsWith("xrange") || message.startsWith("yrange")) { if (message.startsWith("xrange") || message.startsWith("yrange")) {
event.setCancelled(true); event.setCancelled(true);
int range = 0; int range = 0;
try { try {
range = Integer.parseInt(message.split(" ", 2)[1]); range = Integer.parseInt(message.split(" ", 2)[1]);
if (range <= 0) { if (range <= 0) {
range = 0; range = 0;
} }
if (message.startsWith("xrange")) { if (message.startsWith("xrange")) {
xrange = range; xrange = range;
} else { } else {
yrange = range; yrange = range;
} }
if (currentGoal != null) { if (currentGoal != null) {
currentGoal.setXYRange(xrange, yrange); currentGoal.setXYRange(xrange, yrange);
} }
recalculateTree(); recalculateTree();
} catch (Exception ex) { } catch (Exception ex) {
} }
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override @Override
public void run() { public void run() {
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_RANGE_SET, xrange, yrange); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_RANGE_SET, xrange, yrange);
} }
}); });
} else if (message.startsWith("regions")) { } else if (message.startsWith("regions")) {
event.setCancelled(true); event.setCancelled(true);
editingRegions = !editingRegions; editingRegions = !editingRegions;
if (editingRegions) { if (editingRegions) {
for (Location regionCentre : regionCentres) { for (Location regionCentre : regionCentres) {
Entity entity = markers.createMarker(regionCentre, regionCentre); Entity entity = markers.createMarker(regionCentre, regionCentre);
entity.setMetadata("wandermarker", entity.setMetadata("wandermarker",
new FixedMetadataValue(CitizensAPI.getPlugin(), regionCentre)); new FixedMetadataValue(CitizensAPI.getPlugin(), regionCentre));
} }
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override @Override
public void run() { public void run() {
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_REGION_EDITING_START); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_REGION_EDITING_START);
} }
}); });
} else { } else {
markers.destroyMarkers(); markers.destroyMarkers();
} }
} else if (message.startsWith("delay")) { } else if (message.startsWith("delay")) {
event.setCancelled(true); event.setCancelled(true);
try { try {
delay = Integer.parseInt(message.split(" ")[1]); delay = Integer.parseInt(message.split(" ")[1]);
if (currentGoal != null) { if (currentGoal != null) {
currentGoal.setDelay(delay); currentGoal.setDelay(delay);
} }
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override @Override
public void run() { public void run() {
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_DELAY_SET, delay); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_DELAY_SET, delay);
} }
}); });
} catch ( } catch (
Exception e) { Exception e) {
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() { Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override @Override
public void run() { public void run() {
Messaging.sendErrorTr(sender, Messages.WANDER_WAYPOINTS_INVALID_DELAY); Messaging.sendErrorTr(sender, Messages.WANDER_WAYPOINTS_INVALID_DELAY);
} }
}); });
} }
} }
} }
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.getPlayer().equals(sender) || event.getAction() == Action.PHYSICAL || !npc.isSpawned() if (!event.getPlayer().equals(sender) || event.getAction() == Action.PHYSICAL || !npc.isSpawned()
|| event.getPlayer().getWorld() != npc.getEntity().getWorld() || Util.isOffHand(event)) || !editingRegions || event.getPlayer().getWorld() != npc.getEntity().getWorld()
return; || Util.isOffHand(event))
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) { return;
if (event.getClickedBlock() == null) if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR) {
return; if (event.getClickedBlock() == null)
event.setCancelled(true); return;
Location at = event.getClickedBlock().getLocation().add(0, 1, 0); event.setCancelled(true);
if (!regionCentres.contains(at)) { Location at = event.getClickedBlock().getLocation().add(0, 1, 0);
regionCentres.add(at); if (!regionCentres.contains(at)) {
Entity entity = markers.createMarker(at, at); regionCentres.add(at);
entity.setMetadata("wandermarker", new FixedMetadataValue(CitizensAPI.getPlugin(), at)); Entity entity = markers.createMarker(at, at);
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_ADDED_REGION, formatLoc(at), entity.setMetadata("wandermarker", new FixedMetadataValue(CitizensAPI.getPlugin(), at));
regionCentres.size()); Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_ADDED_REGION, formatLoc(at),
recalculateTree(); regionCentres.size());
} recalculateTree();
} }
} }
}
@EventHandler(ignoreCancelled = true) @EventHandler(ignoreCancelled = true)
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (!sender.equals(event.getPlayer()) || !editingRegions || Util.isOffHand(event)) if (!sender.equals(event.getPlayer()) || !editingRegions || Util.isOffHand(event))
return; return;
if (!event.getRightClicked().hasMetadata("wandermarker")) if (!event.getRightClicked().hasMetadata("wandermarker"))
return; return;
regionCentres.remove(event.getRightClicked().getMetadata("wandermarker").get(0).value()); regionCentres.remove(event.getRightClicked().getMetadata("wandermarker").get(0).value());
Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_REMOVED_REGION, markers.removeMarker((Location) event.getRightClicked().getMetadata("wandermarker").get(0).value());
formatLoc((Location) event.getRightClicked().getMetadata("wandermarker").get(0).value()), Messaging.sendTr(sender, Messages.WANDER_WAYPOINTS_REMOVED_REGION,
regionCentres.size()); formatLoc((Location) event.getRightClicked().getMetadata("wandermarker").get(0).value()),
recalculateTree(); regionCentres.size());
} recalculateTree();
}
}; };
} }
@Override @Override
public PhTreeSolid<Boolean> get() { public PhTreeSolid<Boolean> get() {
return regionCentres.isEmpty() ? null : tree; return regionCentres.isEmpty() ? null : tree;
} }
public List<Location> getRegionCentres() { public List<Location> getRegionCentres() {
return new RecalculateList(); return new RecalculateList();
} }
@Override @Override
public boolean isPaused() { public boolean isPaused() {
return paused; return paused;
} }
@Override @Override
public void load(DataKey key) { public void load(DataKey key) {
recalculateTree(); recalculateTree();
} }
@Override @Override
public void onRemove() { public void onRemove() {
npc.getDefaultGoalController().removeGoal(currentGoal); npc.getDefaultGoalController().removeGoal(currentGoal);
} }
@Override @Override
public void onSpawn(NPC npc) { public void onSpawn(NPC npc) {
this.npc = npc; this.npc = npc;
if (currentGoal == null) { if (currentGoal == null) {
currentGoal = WanderGoal.createWithNPCAndRangeAndTreeAndFallback(npc, xrange, yrange, currentGoal = WanderGoal.createWithNPCAndRangeAndTreeAndFallback(npc, xrange, yrange,
WanderWaypointProvider.this, WanderWaypointProvider.this); WanderWaypointProvider.this, WanderWaypointProvider.this);
currentGoal.setDelay(delay); currentGoal.setDelay(delay);
} }
npc.getDefaultGoalController().addGoal(currentGoal, 1); npc.getDefaultGoalController().addGoal(currentGoal, 1);
} }
private void recalculateTree() { private void recalculateTree() {
tree = PhTreeSolid.create(3); tree = PhTreeSolid.create(3);
for (Location loc : regionCentres) { for (Location loc : regionCentres) {
long[] lower = { loc.getBlockX() - xrange, loc.getBlockY() - yrange, loc.getBlockZ() - xrange }; long[] lower = { loc.getBlockX() - xrange, loc.getBlockY() - yrange, loc.getBlockZ() - xrange };
long[] upper = { loc.getBlockX() + xrange, loc.getBlockY() + yrange, loc.getBlockZ() + xrange }; long[] upper = { loc.getBlockX() + xrange, loc.getBlockY() + yrange, loc.getBlockZ() + xrange };
tree.put(lower, upper, true); tree.put(lower, upper, true);
} }
} }
public void removeRegionCentre(Location centre) { public void removeRegionCentre(Location centre) {
regionCentres.remove(centre); regionCentres.remove(centre);
recalculateTree(); recalculateTree();
} }
public void removeRegionCentres(Collection<Location> centre) { public void removeRegionCentres(Collection<Location> centre) {
regionCentres.removeAll(centre); regionCentres.removeAll(centre);
recalculateTree(); recalculateTree();
} }
@Override @Override
public void save(DataKey key) { public void save(DataKey key) {
} }
@Override @Override
public void setPaused(boolean paused) { public void setPaused(boolean paused) {
this.paused = paused; this.paused = paused;
} }
private class RecalculateList extends ForwardingList<Location> { private class RecalculateList extends ForwardingList<Location> {
@Override @Override
public void add(int idx, Location loc) { public void add(int idx, Location loc) {
super.add(idx, loc); super.add(idx, loc);
recalculateTree(); recalculateTree();
} }
@Override @Override
public boolean add(Location loc) { public boolean add(Location loc) {
boolean val = super.add(loc); boolean val = super.add(loc);
recalculateTree(); recalculateTree();
return val; return val;
} }
@Override @Override
protected List<Location> delegate() { protected List<Location> delegate() {
return regionCentres; return regionCentres;
} }
@Override @Override
public Location remove(int idx) { public Location remove(int idx) {
Location val = super.remove(idx); Location val = super.remove(idx);
recalculateTree(); recalculateTree();
return val; return val;
} }
@Override @Override
public Location set(int idx, Location idx2) { public Location set(int idx, Location idx2) {
Location val = super.set(idx, idx2); Location val = super.set(idx, idx2);
recalculateTree(); recalculateTree();
return val; return val;
} }
} }
private static final int DEFAULT_XRANGE = 3; private static final int DEFAULT_XRANGE = 3;
private static final int DEFAULT_YRANGE = 25; private static final int DEFAULT_YRANGE = 25;
} }