mirror of
https://github.com/CitizensDev/Citizens2.git
synced 2025-02-22 07:11:45 +01:00
Fix some bugs with waypoints, add waypoint markers
This commit is contained in:
parent
41ba6b1f64
commit
ffaf616b1b
@ -417,7 +417,7 @@ public class NPCCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0)
|
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0)
|
||||||
public void npc(CommandContext args, CommandSender sender, NPC npc) {
|
public void npc(CommandContext args, CommandSender sender, final NPC npc) {
|
||||||
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
|
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
|
||||||
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
|
Messaging.send(sender, " <a>ID: <e>" + npc.getId());
|
||||||
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType());
|
Messaging.send(sender, " <a>Type: <e>" + npc.getTrait(MobType.class).getType());
|
||||||
|
@ -149,9 +149,8 @@ public class CitizensNavigator implements Navigator {
|
|||||||
private void stopNavigating(CancelReason reason) {
|
private void stopNavigating(CancelReason reason) {
|
||||||
if (!isNavigating())
|
if (!isNavigating())
|
||||||
return;
|
return;
|
||||||
if (reason == CancelReason.STUCK) {
|
if (reason == CancelReason.STUCK && localParams.stuckAction() != null) {
|
||||||
StuckAction action = localParams.stuckAction();
|
StuckAction action = localParams.stuckAction();
|
||||||
if (action != null) {
|
|
||||||
boolean shouldContinue = action.run(npc, this);
|
boolean shouldContinue = action.run(npc, this);
|
||||||
if (shouldContinue) {
|
if (shouldContinue) {
|
||||||
stationaryTicks = 0;
|
stationaryTicks = 0;
|
||||||
@ -159,7 +158,6 @@ public class CitizensNavigator implements Navigator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
NavigationCancelEvent event = new NavigationCancelEvent(this, reason);
|
NavigationCancelEvent event = new NavigationCancelEvent(this, reason);
|
||||||
PathStrategy old = executing;
|
PathStrategy old = executing;
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
@ -188,9 +186,9 @@ public class CitizensNavigator implements Navigator {
|
|||||||
boolean finished = executing.update();
|
boolean finished = executing.update();
|
||||||
if (!finished)
|
if (!finished)
|
||||||
return;
|
return;
|
||||||
if (executing.getCancelReason() != null)
|
if (executing.getCancelReason() != null) {
|
||||||
stopNavigating(executing.getCancelReason());
|
stopNavigating(executing.getCancelReason());
|
||||||
else {
|
} else {
|
||||||
NavigationCompleteEvent event = new NavigationCompleteEvent(this);
|
NavigationCompleteEvent event = new NavigationCompleteEvent(this);
|
||||||
PathStrategy old = executing;
|
PathStrategy old = executing;
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package net.citizensnpcs.trait.waypoint;
|
||||||
|
|
||||||
|
import net.minecraft.server.DamageSource;
|
||||||
|
import net.minecraft.server.EntityEnderCrystal;
|
||||||
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
public class EntityEnderCrystalMarker extends EntityEnderCrystal {
|
||||||
|
public EntityEnderCrystalMarker(World world) {
|
||||||
|
super(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void h_() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean damageEntity(DamageSource damagesource, int i) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package net.citizensnpcs.trait.waypoint;
|
|||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -16,20 +17,26 @@ import net.citizensnpcs.api.npc.NPC;
|
|||||||
import net.citizensnpcs.api.util.DataKey;
|
import net.citizensnpcs.api.util.DataKey;
|
||||||
import net.citizensnpcs.editor.Editor;
|
import net.citizensnpcs.editor.Editor;
|
||||||
import net.citizensnpcs.util.Messaging;
|
import net.citizensnpcs.util.Messaging;
|
||||||
|
import net.citizensnpcs.util.NMS;
|
||||||
import net.citizensnpcs.util.StringHelper;
|
import net.citizensnpcs.util.StringHelper;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.AsyncPlayerChatEvent;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerItemHeldEvent;
|
import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.Iterators;
|
import com.google.common.collect.Iterators;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
public class LinearWaypointProvider implements WaypointProvider {
|
public class LinearWaypointProvider implements WaypointProvider {
|
||||||
private LinearWaypointGoal currentGoal;
|
private LinearWaypointGoal currentGoal;
|
||||||
@ -41,19 +48,32 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
return new Editor() {
|
return new Editor() {
|
||||||
boolean editing = true;
|
boolean editing = true;
|
||||||
int editingSlot = waypoints.size() - 1;
|
int editingSlot = waypoints.size() - 1;
|
||||||
|
Map<Waypoint, Entity> waypointEntities = Maps.newHashMap();
|
||||||
|
private boolean showPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void begin() {
|
public void begin() {
|
||||||
player.sendMessage(ChatColor.AQUA + "Entered the linear waypoint editor!");
|
Messaging.send(player, ChatColor.AQUA + "Entered the linear waypoint editor!");
|
||||||
Messaging.send(player, "<e>Left click<a> to add a waypoint, <e>right click<a> to remove.");
|
Messaging.send(player, "<e>Left click<a> to add a waypoint, <e>right click<a> to remove.");
|
||||||
|
Messaging.send(player, "<a>Type <e>toggle path<a> to toggle showing entities at waypoints.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createWaypointMarker(Waypoint waypoint) {
|
||||||
|
Entity entity = spawnMarker(player.getWorld(), waypoint.getLocation().add(0, 1, 0));
|
||||||
|
if (entity == null)
|
||||||
|
return;
|
||||||
|
waypointEntities.put(waypoint, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void end() {
|
public void end() {
|
||||||
if (!editing)
|
if (!editing)
|
||||||
return;
|
return;
|
||||||
player.sendMessage(ChatColor.AQUA + "Exited the linear waypoint editor.");
|
Messaging.send(player, ChatColor.AQUA + "Exited the linear waypoint editor.");
|
||||||
editing = false;
|
editing = false;
|
||||||
|
if (!showPath)
|
||||||
|
return;
|
||||||
|
destroyWaypointMarkers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatLoc(Location location) {
|
private String formatLoc(Location location) {
|
||||||
@ -82,6 +102,44 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
Editor.leave(player);
|
Editor.leave(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
|
if (!event.getPlayer().equals(player))
|
||||||
|
return;
|
||||||
|
if (!event.getMessage().equalsIgnoreCase("toggle path"))
|
||||||
|
return;
|
||||||
|
event.setCancelled(true);
|
||||||
|
// we need to spawn entities, get back on the main thread.
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
togglePath();
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void togglePath() {
|
||||||
|
showPath = !showPath;
|
||||||
|
if (showPath) {
|
||||||
|
createWaypointMarkers();
|
||||||
|
Messaging.sendF(player, "%s waypoint markers.", StringHelper.wrap("Showing"));
|
||||||
|
} else {
|
||||||
|
destroyWaypointMarkers();
|
||||||
|
Messaging.sendF(player, "%s showing waypoint markers.", StringHelper.wrap("Stopped"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createWaypointMarkers() {
|
||||||
|
for (Waypoint waypoint : waypoints)
|
||||||
|
createWaypointMarker(waypoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyWaypointMarkers() {
|
||||||
|
for (Entity entity : waypointEntities.values())
|
||||||
|
entity.remove();
|
||||||
|
waypointEntities.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL)
|
if (!event.getPlayer().equals(player) || event.getAction() == Action.PHYSICAL)
|
||||||
@ -98,18 +156,20 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
|
|
||||||
if (prev != null) {
|
if (prev != null) {
|
||||||
double distance = at.distanceSquared(prev);
|
double distance = at.distanceSquared(prev);
|
||||||
double maxDistance = npc.getNavigator().getDefaultParameters().range();
|
double maxDistance = Math.pow(npc.getNavigator().getDefaultParameters().range(), 2);
|
||||||
maxDistance = Math.pow(maxDistance, 2);
|
|
||||||
if (distance > maxDistance) {
|
if (distance > maxDistance) {
|
||||||
Messaging.sendF(player, ChatColor.RED
|
Messaging.sendF(player, ChatColor.RED
|
||||||
+ "Previous waypoint is %s blocks away but the distance limit is %s.",
|
+ "Previous waypoint is %s blocks away but the distance limit is %s.",
|
||||||
StringHelper.wrap(distance, ChatColor.RED),
|
StringHelper.wrap(Math.sqrt(distance), ChatColor.RED),
|
||||||
StringHelper.wrap(maxDistance, ChatColor.RED));
|
StringHelper.wrap(Math.sqrt(maxDistance), ChatColor.RED));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints.add(Math.max(0, editingSlot), new Waypoint(at));
|
Waypoint element = new Waypoint(at);
|
||||||
|
waypoints.add(Math.max(0, editingSlot), element);
|
||||||
|
if (showPath)
|
||||||
|
createWaypointMarker(element);
|
||||||
editingSlot = Math.min(editingSlot + 1, waypoints.size());
|
editingSlot = Math.min(editingSlot + 1, waypoints.size());
|
||||||
Messaging.send(
|
Messaging.send(
|
||||||
player,
|
player,
|
||||||
@ -118,7 +178,9 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
} else if (waypoints.size() > 0) {
|
} else if (waypoints.size() > 0) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
editingSlot = Math.min(0, Math.max(waypoints.size() - 1, editingSlot));
|
editingSlot = Math.min(0, Math.max(waypoints.size() - 1, editingSlot));
|
||||||
waypoints.remove(editingSlot);
|
Waypoint waypoint = waypoints.remove(editingSlot);
|
||||||
|
if (showPath)
|
||||||
|
removeWaypointMarker(waypoint);
|
||||||
editingSlot = Math.max(0, editingSlot - 1);
|
editingSlot = Math.max(0, editingSlot - 1);
|
||||||
Messaging.send(player, String.format(
|
Messaging.send(player, String.format(
|
||||||
"<e>Removed<a> a waypoint (<e>%d<a> remaining) (<e>%d<a>)", waypoints.size(),
|
"<e>Removed<a> a waypoint (<e>%d<a> remaining) (<e>%d<a>)", waypoints.size(),
|
||||||
@ -151,6 +213,17 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
+ formatLoc(waypoints.get(editingSlot).getLocation()) + ").");
|
+ formatLoc(waypoints.get(editingSlot).getLocation()) + ").");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeWaypointMarker(Waypoint waypoint) {
|
||||||
|
Entity entity = waypointEntities.remove(waypoint);
|
||||||
|
if (entity != null)
|
||||||
|
entity.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Entity spawnMarker(World world, Location at) {
|
||||||
|
return NMS.spawnCustomEntity(world, at, EntityEnderCrystalMarker.class,
|
||||||
|
EntityType.ENDER_CRYSTAL);
|
||||||
|
}
|
||||||
|
|
||||||
private static final int LARGEST_SLOT = 8;
|
private static final int LARGEST_SLOT = 8;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -224,7 +297,7 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onNavigationComplete(NavigationCompleteEvent event) {
|
public void onNavigationComplete(NavigationCompleteEvent event) {
|
||||||
if (currentDestination == null || !event.getNavigator().equals(getNavigator()))
|
if (selector == null || !event.getNavigator().equals(getNavigator()))
|
||||||
return;
|
return;
|
||||||
selector.finish();
|
selector.finish();
|
||||||
}
|
}
|
||||||
@ -243,6 +316,8 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(GoalSelector selector) {
|
public void run(GoalSelector selector) {
|
||||||
|
if (!getNavigator().isNavigating())
|
||||||
|
selector.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPaused(boolean pause) {
|
public void setPaused(boolean pause) {
|
||||||
@ -254,8 +329,9 @@ public class LinearWaypointProvider implements WaypointProvider {
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(GoalSelector selector) {
|
public boolean shouldExecute(GoalSelector selector) {
|
||||||
if (paused || currentDestination != null || !npc.isSpawned() || getNavigator().isNavigating()
|
if (paused || currentDestination != null || !npc.isSpawned() || getNavigator().isNavigating()
|
||||||
|| waypoints.size() == 0)
|
|| waypoints.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
if (waypoints.size() == 1) {
|
if (waypoints.size() == 1) {
|
||||||
// avoid pathing to the same point and wasting memory.
|
// avoid pathing to the same point and wasting memory.
|
||||||
Location dest = npc.getBukkitEntity().getLocation();
|
Location dest = npc.getBukkitEntity().getLocation();
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package net.citizensnpcs.util;
|
package net.citizensnpcs.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import net.citizensnpcs.npc.CitizensNPC;
|
import net.citizensnpcs.npc.CitizensNPC;
|
||||||
import net.minecraft.server.ControllerLook;
|
import net.minecraft.server.ControllerLook;
|
||||||
@ -14,6 +16,7 @@ import net.minecraft.server.NetworkManager;
|
|||||||
import net.minecraft.server.PathfinderGoalSelector;
|
import net.minecraft.server.PathfinderGoalSelector;
|
||||||
import net.minecraft.server.World;
|
import net.minecraft.server.World;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
|
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
@ -28,6 +31,7 @@ public class NMS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final float DEFAULT_SPEED = 0.4F;
|
private static final float DEFAULT_SPEED = 0.4F;
|
||||||
|
private static final Map<Class<? extends Entity>, Constructor<? extends Entity>> ENTITY_CONSTRUCTOR_CACHE = new WeakHashMap<Class<? extends Entity>, Constructor<? extends Entity>>();
|
||||||
private static Map<Class<? extends Entity>, Integer> ENTITY_CLASS_TO_INT;
|
private static Map<Class<? extends Entity>, Integer> ENTITY_CLASS_TO_INT;
|
||||||
private static Map<Integer, Class<? extends Entity>> ENTITY_INT_TO_CLASS;
|
private static Map<Integer, Class<? extends Entity>> ENTITY_INT_TO_CLASS;
|
||||||
private static Field GOAL_FIELD;
|
private static Field GOAL_FIELD;
|
||||||
@ -183,4 +187,32 @@ public class NMS {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static org.bukkit.entity.Entity spawnCustomEntity(org.bukkit.World world, Location at,
|
||||||
|
Class<? extends Entity> clazz, EntityType type) {
|
||||||
|
World handle = ((CraftWorld) world).getHandle();
|
||||||
|
Entity entity = null;
|
||||||
|
try {
|
||||||
|
Constructor<? extends Entity> constructor = getCustomEntityConstructor(clazz, type);
|
||||||
|
entity = constructor.newInstance(handle);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
handle.addEntity(entity);
|
||||||
|
entity.setLocation(at.getX(), at.getY(), at.getZ(), at.getYaw(), at.getPitch());
|
||||||
|
return entity.getBukkitEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Constructor<? extends Entity> getCustomEntityConstructor(Class<? extends Entity> clazz,
|
||||||
|
EntityType type) throws SecurityException, NoSuchMethodException {
|
||||||
|
Constructor<? extends Entity> constructor = ENTITY_CONSTRUCTOR_CACHE.get(clazz);
|
||||||
|
if (constructor == null) {
|
||||||
|
constructor = clazz.getConstructor(World.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
ENTITY_CLASS_TO_INT.put(clazz, (int) type.getTypeId());
|
||||||
|
ENTITY_CONSTRUCTOR_CACHE.put(clazz, constructor);
|
||||||
|
}
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user