diff --git a/pom.xml b/pom.xml index 9be10eed..16d987b6 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,14 @@ sk89q-repo https://maven.enginehub.org/repo/ - + + + jitpack.io + https://jitpack.io + + false + + @@ -28,18 +35,6 @@ spigot-api ${bukkit.version} provided - - - org.powermock - powermock-module-junit4 - ${powermock.version} - test - - - org.powermock - powermock-api-mockito - ${powermock.version} - test me.clip @@ -53,6 +48,12 @@ ${worldguard.version} provided + + com.github.MilkBowl + VaultAPI + 1.7 + provided + ch.ethz.globis.phtree phtree diff --git a/src/main/java/net/citizensnpcs/api/LocationLookup.java b/src/main/java/net/citizensnpcs/api/LocationLookup.java index bebbe4d4..de9e1f70 100644 --- a/src/main/java/net/citizensnpcs/api/LocationLookup.java +++ b/src/main/java/net/citizensnpcs/api/LocationLookup.java @@ -121,6 +121,12 @@ public boolean remove(UUID key, String value) { return sent.getOrDefault(key, Collections.emptyMap()).remove(value) != null; } + public void removeAllValues(String value) { + for (Map map : sent.values()) { + map.remove(value); + } + } + public void set(UUID key, String value, T marker) { if (marker instanceof Location || marker instanceof World) { throw new IllegalArgumentException("Invalid marker"); diff --git a/src/main/java/net/citizensnpcs/api/ai/NavigatorParameters.java b/src/main/java/net/citizensnpcs/api/ai/NavigatorParameters.java index 13d44db2..1500a323 100644 --- a/src/main/java/net/citizensnpcs/api/ai/NavigatorParameters.java +++ b/src/main/java/net/citizensnpcs/api/ai/NavigatorParameters.java @@ -1,6 +1,7 @@ package net.citizensnpcs.api.ai; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.bukkit.Location; @@ -320,6 +321,10 @@ public BlockExaminer[] examiners() { return examiners.toArray(new BlockExaminer[examiners.size()]); } + public boolean hasExaminer(Class clazz) { + return Arrays.asList(examiners).stream().anyMatch(e -> clazz.isAssignableFrom(e.getClass())); + } + /** * @see #lookAtFunction(Function) */ diff --git a/src/main/java/net/citizensnpcs/api/astar/pathfinder/Path.java b/src/main/java/net/citizensnpcs/api/astar/pathfinder/Path.java index 2ac4ca86..5c24567a 100644 --- a/src/main/java/net/citizensnpcs/api/astar/pathfinder/Path.java +++ b/src/main/java/net/citizensnpcs/api/astar/pathfinder/Path.java @@ -4,11 +4,10 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; -import org.bukkit.Bukkit; -import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.entity.Player; import org.bukkit.util.Vector; import com.google.common.base.Function; @@ -19,7 +18,6 @@ import net.citizensnpcs.api.astar.Plan; import net.citizensnpcs.api.astar.pathfinder.PathPoint.PathCallback; import net.citizensnpcs.api.npc.NPC; -import net.citizensnpcs.api.util.SpigotUtil; public class Path implements Plan { private List blockList; @@ -50,29 +48,10 @@ private PathEntry[] cull(Iterable unfiltered) { return path.toArray(new PathEntry[path.size()]); } - public void debug() { - for (Player player : Bukkit.getOnlinePlayers()) { - for (PathEntry entry : path) { - if (SpigotUtil.isUsing1_13API()) { - player.sendBlockChange(entry.vector.toLocation(player.getWorld()), YELLOW_FLOWER.createBlockData()); - } else { - player.sendBlockChange(entry.vector.toLocation(player.getWorld()), YELLOW_FLOWER, (byte) 0); - } - } - } - } - - public void debugEnd() { - for (Player player : Bukkit.getOnlinePlayers()) { - for (PathEntry entry : path) { - Block block = entry.vector.toLocation(player.getWorld()).getBlock(); - if (SpigotUtil.isUsing1_13API()) { - player.sendBlockChange(block.getLocation(), block.getBlockData()); - } else { - player.sendBlockChange(block.getLocation(), block.getType(), block.getData()); - } - } - } + public List getBlocks(World world) { + return Arrays.asList(path).stream() + .map(p -> world.getBlockAt(p.vector.getBlockX(), p.vector.getBlockY(), p.vector.getBlockZ())) + .collect(Collectors.toList()); } public Vector getCurrentVector() { @@ -154,7 +133,4 @@ public String toString() { return vector.toString(); } } - - private static Material YELLOW_FLOWER = SpigotUtil.isUsing1_13API() ? Material.SUNFLOWER - : Material.valueOf("YELLOW_FLOWER"); } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/command/CommandManager.java b/src/main/java/net/citizensnpcs/api/command/CommandManager.java index 6afc6f0c..caaaeadb 100644 --- a/src/main/java/net/citizensnpcs/api/command/CommandManager.java +++ b/src/main/java/net/citizensnpcs/api/command/CommandManager.java @@ -5,6 +5,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -178,6 +179,8 @@ private void executeCommand(String[] args, CommandSender sender, Object[] method val = CommandContext.parseLocation(context.getSenderLocation(), val.toString()); } else if (desiredType == UUID.class) { val = UUID.fromString(val.toString()); + } else if (desiredType == Duration.class) { + val = SpigotUtil.parseDuration(val.toString()); } methodArgs[entry.getKey()] = val; } @@ -590,7 +593,7 @@ public void setInjector(Injector injector) { this.injector = injector; } - public static class CommandInfo { + public class CommandInfo { private List annotations = Lists.newArrayList(); private final Command commandAnnotation; public Object instance; @@ -605,11 +608,11 @@ public CommandInfo(Command commandAnnotation, Method method) { } public void addArgAnnotation(int idx, Class paramType, Arg arg) { - this.methodArguments.put(idx, new InjectedCommandArgument(paramType, arg)); + this.methodArguments.put(idx, new InjectedCommandArgument(injector, paramType, arg)); } public void addFlagAnnotation(int idx, Class paramType, Flag flag) { - this.methodArguments.put(idx, new InjectedCommandArgument(paramType, flag)); + this.methodArguments.put(idx, new InjectedCommandArgument(injector, paramType, flag)); } private Collection calculateValueFlags() { @@ -687,29 +690,21 @@ private static class InjectedCommandArgument { private final Class paramType; private FlagValidator validator; - public InjectedCommandArgument(Class paramType, Arg arg) { + public InjectedCommandArgument(Injector injector, Class paramType, Arg arg) { this.paramType = paramType; this.names = new String[] {}; this.index = arg.value(); this.completions = arg.completions(); this.defaultValue = arg.defValue().isEmpty() ? null : arg.defValue(); if (arg.validator() != FlagValidator.Identity.class) { - try { - this.validator = arg.validator().getConstructor().newInstance(); - } catch (Exception e) { - e.printStackTrace(); - } + this.validator = (FlagValidator) injector.getInstance(arg.validator()); } if (arg.completionsProvider() != CompletionsProvider.Identity.class) { - try { - this.completionsProvider = arg.completionsProvider().getConstructor().newInstance(); - } catch (Exception e) { - e.printStackTrace(); - } + this.completionsProvider = (CompletionsProvider) injector.getInstance(arg.completionsProvider()); } } - public InjectedCommandArgument(Class paramType, Flag flag) { + public InjectedCommandArgument(Injector injector, Class paramType, Flag flag) { this.paramType = paramType; this.names = flag.value(); for (int i = 0; i < this.names.length; i++) { @@ -718,18 +713,10 @@ public InjectedCommandArgument(Class paramType, Flag flag) { this.completions = flag.completions(); this.defaultValue = flag.defValue().isEmpty() ? null : flag.defValue(); if (flag.validator() != FlagValidator.Identity.class) { - try { - this.validator = flag.validator().getConstructor().newInstance(); - } catch (Exception e) { - e.printStackTrace(); - } + this.validator = (FlagValidator) injector.getInstance(flag.validator()); } if (flag.completionsProvider() != CompletionsProvider.Identity.class) { - try { - this.completionsProvider = flag.completionsProvider().getConstructor().newInstance(); - } catch (Exception e) { - e.printStackTrace(); - } + this.completionsProvider = (CompletionsProvider) injector.getInstance(flag.completionsProvider()); } } diff --git a/src/main/java/net/citizensnpcs/api/command/Injector.java b/src/main/java/net/citizensnpcs/api/command/Injector.java index fb573d56..8399225a 100644 --- a/src/main/java/net/citizensnpcs/api/command/Injector.java +++ b/src/main/java/net/citizensnpcs/api/command/Injector.java @@ -1,16 +1,19 @@ package net.citizensnpcs.api.command; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; import net.citizensnpcs.api.util.Messaging; public class Injector { private final Class[] argClasses; - private final Object[] args; + private final List args; public Injector(Object... args) { - this.args = args; + this.args = Arrays.asList(args); argClasses = new Class[args.length]; for (int i = 0; i < args.length; ++i) { argClasses[i] = args[i].getClass(); @@ -19,29 +22,24 @@ public Injector(Object... args) { public Object getInstance(Class clazz) { try { - Constructor ctr = clazz.getConstructor(argClasses); - ctr.setAccessible(true); - return ctr.newInstance(args); + return LOOKUP.findConstructor(clazz, MethodType.methodType(void.class, argClasses)) + .invokeWithArguments(args); } catch (NoSuchMethodException e) { try { - return clazz.newInstance(); + Constructor ctr = clazz.getDeclaredConstructor(); + ctr.setAccessible(true); + return ctr.newInstance(); } catch (Exception ex) { Messaging.severe("Error initializing commands class " + clazz + ": "); ex.printStackTrace(); return null; } - } catch (InvocationTargetException e) { - Messaging.severe("Error initializing commands class " + clazz + ": "); - e.printStackTrace(); - return null; - } catch (InstantiationException e) { - Messaging.severe("Error initializing commands class " + clazz + ": "); - e.printStackTrace(); - return null; - } catch (IllegalAccessException e) { + } catch (Throwable e) { Messaging.severe("Error initializing commands class " + clazz + ": "); e.printStackTrace(); return null; } } + + private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); } \ No newline at end of file diff --git a/src/main/java/net/citizensnpcs/api/npc/NPC.java b/src/main/java/net/citizensnpcs/api/npc/NPC.java index a7788960..ff1a9351 100644 --- a/src/main/java/net/citizensnpcs/api/npc/NPC.java +++ b/src/main/java/net/citizensnpcs/api/npc/NPC.java @@ -491,6 +491,7 @@ public enum Metadata { * The packet update delay. Integer defaults to setting value. */ PACKET_UPDATE_DELAY("packet-update-delay"), + PATHFINDER_FALL_DISTANCE("pathfinder-fall-distance"), /** * Whether to open doors while pathfinding. Boolean. */ diff --git a/src/main/java/net/citizensnpcs/api/trait/trait/PlayerFilter.java b/src/main/java/net/citizensnpcs/api/trait/trait/PlayerFilter.java index ee61cc87..4d7e1c3f 100644 --- a/src/main/java/net/citizensnpcs/api/trait/trait/PlayerFilter.java +++ b/src/main/java/net/citizensnpcs/api/trait/trait/PlayerFilter.java @@ -4,7 +4,9 @@ import java.util.UUID; import java.util.function.Function; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.plugin.RegisteredServiceProvider; import com.google.common.collect.Sets; @@ -17,12 +19,28 @@ public class PlayerFilter extends Trait { @Persist private Set allowlist = null; @Persist + private Set groupAllowlist = null; + @Persist + private Set groupHidden = null; + @Persist private Set hidden = null; private Function hideFunction = (p) -> { if (allowlist != null && !allowlist.contains(p.getUniqueId())) return true; if (hidden != null && hidden.contains(p.getUniqueId())) return true; + if (groupAllowlist != null || groupHidden != null) { + RegisteredServiceProvider groups = Bukkit.getServicesManager() + .getRegistration(net.milkbowl.vault.permission.Permission.class); + if (groups != null + && !groupAllowlist.stream().anyMatch(group -> groups.getProvider().playerInGroup(p, group))) { + return true; + } + if (groups != null + && groupHidden.stream().anyMatch(group -> groups.getProvider().playerInGroup(p, group))) { + return true; + } + } return false; }; @@ -32,6 +50,7 @@ public PlayerFilter() { public void clear() { hidden = allowlist = null; + groupAllowlist = groupHidden = null; } public void hide(UUID uuid) { @@ -41,8 +60,17 @@ public void hide(UUID uuid) { hidden.add(uuid); } + public void hideGroup(String group) { + if (groupHidden == null) { + groupHidden = Sets.newHashSet(); + } + groupHidden.add(group); + } + public boolean isHidden(Player player) { - return hideFunction == null ? false : hideFunction.apply(player); + if (hideFunction == null) + return false; + return hideFunction.apply(player); } public void only(UUID uuid) { @@ -52,6 +80,13 @@ public void only(UUID uuid) { allowlist.add(uuid); } + public void onlyGroup(String group) { + if (groupAllowlist == null) { + groupAllowlist = Sets.newHashSet(); + } + groupAllowlist.add(group); + } + public void setPlayerFilter(Function filter) { this.hideFunction = filter; } @@ -60,8 +95,23 @@ public void unhide(UUID uuid) { if (hidden != null) { hidden.remove(uuid); } + if (hidden.size() == 0) { + hidden = null; + } if (allowlist != null) { allowlist.remove(uuid); } } + + public void unhideGroup(String group) { + if (groupHidden != null) { + groupHidden.remove(group); + } + if (groupHidden.size() == 0) { + groupHidden = null; + } + if (groupAllowlist != null) { + groupAllowlist = null; + } + } } diff --git a/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java b/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java index 4d5744a1..54d38f99 100644 --- a/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java +++ b/src/main/java/net/citizensnpcs/api/util/SpigotUtil.java @@ -1,10 +1,15 @@ package net.citizensnpcs.api.util; +import java.time.Duration; +import java.util.regex.Pattern; + import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; +import com.google.common.primitives.Ints; + public class SpigotUtil { public static boolean checkYSafe(double y, World world) { if (!SUPPORT_WORLD_HEIGHT || world == null) { @@ -48,7 +53,20 @@ public static boolean isUsing1_13API() { return using1_13API; } + public static Duration parseDuration(String raw) { + Integer ticks = Ints.tryParse(raw.endsWith("t") ? raw.substring(0, raw.length() - 1) : raw); + if (ticks != null) { + return Duration.ofMillis(ticks * 50); + } + raw = NUMBER_MATCHER.matcher(raw).replaceFirst("P$1T").replace("min", "m").replace("hr", "h"); + if (raw.charAt(0) != 'P') { + raw = "PT" + raw; + } + return Duration.parse(raw); + } + private static int[] BUKKIT_VERSION = null; + private static Pattern NUMBER_MATCHER = Pattern.compile("(\\d+d)"); private static boolean SUPPORT_WORLD_HEIGHT = true; private static Boolean using1_13API; }