2019-09-23 14:29:31 +02:00
|
|
|
package net.citizensnpcs.trait;
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.command.CommandSender;
|
|
|
|
import org.bukkit.entity.Player;
|
2020-04-30 15:32:38 +02:00
|
|
|
import org.bukkit.permissions.PermissionAttachment;
|
2019-09-23 14:29:31 +02:00
|
|
|
|
2020-04-25 13:10:49 +02:00
|
|
|
import com.google.common.base.Splitter;
|
2019-09-23 14:29:31 +02:00
|
|
|
import com.google.common.collect.Lists;
|
|
|
|
import com.google.common.collect.Maps;
|
2020-04-25 13:10:49 +02:00
|
|
|
import com.google.common.io.ByteArrayDataOutput;
|
|
|
|
import com.google.common.io.ByteStreams;
|
2019-09-23 14:29:31 +02:00
|
|
|
|
2020-04-15 21:04:42 +02:00
|
|
|
import net.citizensnpcs.api.CitizensAPI;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
2019-10-01 08:16:00 +02:00
|
|
|
import net.citizensnpcs.api.persistence.DelegatePersistence;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.api.persistence.Persist;
|
2020-02-22 05:57:03 +01:00
|
|
|
import net.citizensnpcs.api.persistence.PersistenceLoader;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.api.persistence.Persister;
|
|
|
|
import net.citizensnpcs.api.trait.Trait;
|
|
|
|
import net.citizensnpcs.api.trait.TraitName;
|
|
|
|
import net.citizensnpcs.api.util.DataKey;
|
|
|
|
import net.citizensnpcs.api.util.Messaging;
|
2020-01-16 12:40:32 +01:00
|
|
|
import net.citizensnpcs.api.util.Placeholders;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.util.Messages;
|
2020-05-01 14:07:22 +02:00
|
|
|
import net.citizensnpcs.util.StringHelper;
|
2019-09-23 14:29:31 +02:00
|
|
|
|
|
|
|
@TraitName("commandtrait")
|
|
|
|
public class CommandTrait extends Trait {
|
|
|
|
@Persist
|
2019-10-01 08:16:00 +02:00
|
|
|
@DelegatePersistence(NPCCommandPersister.class)
|
2019-09-23 14:29:31 +02:00
|
|
|
private final Map<String, NPCCommand> commands = Maps.newHashMap();
|
2020-02-22 05:57:03 +01:00
|
|
|
@Persist
|
|
|
|
@DelegatePersistence(PlayerNPCCommandPersister.class)
|
2020-03-07 05:43:16 +01:00
|
|
|
private final Map<String, PlayerNPCCommand> cooldowns = Maps.newHashMap();
|
2020-04-30 15:32:38 +02:00
|
|
|
@Persist
|
|
|
|
private final List<String> temporaryPermissions = Lists.newArrayList();
|
2019-09-23 14:29:31 +02:00
|
|
|
|
|
|
|
public CommandTrait() {
|
|
|
|
super("commandtrait");
|
|
|
|
}
|
|
|
|
|
2020-04-30 15:15:24 +02:00
|
|
|
public int addCommand(NPCCommandBuilder builder) {
|
2019-09-23 14:29:31 +02:00
|
|
|
int id = getNewId();
|
2020-04-30 15:15:24 +02:00
|
|
|
commands.put(String.valueOf(id), builder.build(String.valueOf(id)));
|
2019-09-23 14:29:31 +02:00
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-02-14 15:48:40 +01:00
|
|
|
* Send a brief description of the current state of the trait to the supplied {@link CommandSender}.
|
2019-09-23 14:29:31 +02:00
|
|
|
*/
|
|
|
|
public void describe(CommandSender sender) {
|
|
|
|
List<NPCCommand> left = Lists.newArrayList();
|
|
|
|
List<NPCCommand> right = Lists.newArrayList();
|
|
|
|
for (NPCCommand command : commands.values()) {
|
2020-01-17 10:11:23 +01:00
|
|
|
if (command.hand == Hand.LEFT || command.hand == Hand.BOTH) {
|
2019-09-23 14:29:31 +02:00
|
|
|
left.add(command);
|
2020-01-17 10:11:23 +01:00
|
|
|
}
|
|
|
|
if (command.hand == Hand.RIGHT || command.hand == Hand.BOTH) {
|
2019-09-23 14:29:31 +02:00
|
|
|
right.add(command);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
String output = "";
|
|
|
|
if (left.size() > 0) {
|
|
|
|
output += Messaging.tr(Messages.COMMAND_LEFT_HAND_HEADER);
|
|
|
|
for (NPCCommand command : left) {
|
2020-02-22 05:57:03 +01:00
|
|
|
output += describe(command);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (right.size() > 0) {
|
|
|
|
output += Messaging.tr(Messages.COMMAND_RIGHT_HAND_HEADER);
|
|
|
|
for (NPCCommand command : right) {
|
2020-02-22 05:57:03 +01:00
|
|
|
output += describe(command);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (output.isEmpty()) {
|
|
|
|
output = Messaging.tr(Messages.COMMAND_NO_COMMANDS_ADDED);
|
|
|
|
}
|
|
|
|
Messaging.send(sender, output);
|
|
|
|
}
|
|
|
|
|
2020-02-22 05:57:03 +01:00
|
|
|
private String describe(NPCCommand command) {
|
2020-05-01 14:07:22 +02:00
|
|
|
String output = "<br> - [" + StringHelper.wrap(command.id) + "]: " + command.command + " ["
|
|
|
|
+ StringHelper.wrap(command.cooldown + "s") + "]";
|
2020-02-22 05:57:03 +01:00
|
|
|
if (command.op) {
|
|
|
|
output += " -o";
|
|
|
|
}
|
|
|
|
if (command.player) {
|
|
|
|
output += " -p";
|
|
|
|
}
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
2020-04-15 21:04:42 +02:00
|
|
|
public void dispatch(final Player player, final Hand hand) {
|
|
|
|
Runnable task = new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
for (NPCCommand command : commands.values()) {
|
|
|
|
if (command.hand != hand && command.hand != Hand.BOTH)
|
|
|
|
continue;
|
2020-04-30 15:15:24 +02:00
|
|
|
Runnable runnable = new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2020-05-05 15:53:12 +02:00
|
|
|
PlayerNPCCommand info = cooldowns.get(player.getUniqueId().toString());
|
|
|
|
if (info == null && (command.cooldown > 0 || command.n > 0)) {
|
|
|
|
cooldowns.put(player.getUniqueId().toString(), info = new PlayerNPCCommand());
|
|
|
|
}
|
|
|
|
if (info != null && !info.canUse(player, command)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-30 17:11:45 +02:00
|
|
|
PermissionAttachment attachment = player.addAttachment(CitizensAPI.getPlugin());
|
2020-04-30 15:32:38 +02:00
|
|
|
if (temporaryPermissions.size() > 0) {
|
|
|
|
for (String permission : temporaryPermissions) {
|
|
|
|
attachment.setPermission(permission, true);
|
|
|
|
}
|
|
|
|
}
|
2020-04-30 15:15:24 +02:00
|
|
|
command.run(npc, player);
|
2020-04-30 15:32:38 +02:00
|
|
|
attachment.remove();
|
2020-04-30 15:15:24 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
if (command.delay <= 0) {
|
|
|
|
runnable.run();
|
|
|
|
} else {
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), runnable, command.delay);
|
2020-04-15 21:04:42 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-22 05:57:03 +01:00
|
|
|
}
|
2020-04-15 21:04:42 +02:00
|
|
|
};
|
|
|
|
if (Bukkit.isPrimaryThread()) {
|
|
|
|
task.run();
|
|
|
|
} else {
|
2020-04-30 15:15:24 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), task);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private int getNewId() {
|
|
|
|
int i = 0;
|
|
|
|
while (commands.containsKey(String.valueOf(i))) {
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasCommandId(int id) {
|
|
|
|
return commands.containsKey(String.valueOf(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
public void removeCommandById(int id) {
|
|
|
|
commands.remove(String.valueOf(id));
|
|
|
|
}
|
|
|
|
|
2020-04-30 15:32:38 +02:00
|
|
|
public void setTemporaryPermissions(List<String> permissions) {
|
|
|
|
temporaryPermissions.clear();
|
|
|
|
temporaryPermissions.addAll(permissions);
|
|
|
|
}
|
|
|
|
|
2019-10-01 08:16:00 +02:00
|
|
|
public static enum Hand {
|
2020-02-14 15:48:40 +01:00
|
|
|
BOTH,
|
|
|
|
LEFT,
|
|
|
|
RIGHT;
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private static class NPCCommand {
|
2020-04-25 13:10:49 +02:00
|
|
|
String bungeeServer;
|
2019-09-23 14:29:31 +02:00
|
|
|
String command;
|
2020-02-22 05:57:03 +01:00
|
|
|
int cooldown;
|
2020-04-30 15:15:24 +02:00
|
|
|
int delay;
|
2019-09-23 14:29:31 +02:00
|
|
|
Hand hand;
|
|
|
|
String id;
|
2020-03-03 16:40:42 +01:00
|
|
|
int n;
|
2019-12-29 14:14:38 +01:00
|
|
|
boolean op;
|
2020-03-02 16:40:13 +01:00
|
|
|
List<String> perms;
|
2020-02-22 05:57:03 +01:00
|
|
|
boolean player;
|
2019-09-23 14:29:31 +02:00
|
|
|
|
2020-03-02 16:40:13 +01:00
|
|
|
public NPCCommand(String id, String command, Hand hand, boolean player, boolean op, int cooldown,
|
2020-04-30 15:15:24 +02:00
|
|
|
List<String> perms, int n, int delay) {
|
2019-09-23 14:29:31 +02:00
|
|
|
this.id = id;
|
|
|
|
this.command = command;
|
|
|
|
this.hand = hand;
|
2019-12-02 04:27:15 +01:00
|
|
|
this.player = player;
|
2019-12-29 14:14:38 +01:00
|
|
|
this.op = op;
|
2020-02-22 05:57:03 +01:00
|
|
|
this.cooldown = cooldown;
|
2020-03-02 16:40:13 +01:00
|
|
|
this.perms = perms;
|
2020-03-03 16:40:42 +01:00
|
|
|
this.n = n;
|
2020-04-30 15:15:24 +02:00
|
|
|
this.delay = delay;
|
2020-04-25 13:10:49 +02:00
|
|
|
List<String> split = Splitter.on(' ').omitEmptyStrings().trimResults().splitToList(command);
|
|
|
|
this.bungeeServer = split.size() == 2 && split.get(0).equalsIgnoreCase("server") ? split.get(1) : null;
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void run(NPC npc, Player clicker) {
|
2020-01-16 12:40:32 +01:00
|
|
|
String interpolatedCommand = Placeholders.replace(command, clicker, npc);
|
2020-04-30 15:15:24 +02:00
|
|
|
if (!player) {
|
2019-12-02 04:27:15 +01:00
|
|
|
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), interpolatedCommand);
|
2020-04-30 15:15:24 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
boolean wasOp = clicker.isOp();
|
|
|
|
if (op) {
|
|
|
|
clicker.setOp(true);
|
2019-12-02 04:27:15 +01:00
|
|
|
}
|
2020-04-30 18:40:27 +02:00
|
|
|
|
2020-04-30 15:15:24 +02:00
|
|
|
if (bungeeServer != null) {
|
|
|
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
|
|
|
out.writeUTF("Connect");
|
|
|
|
out.writeUTF(bungeeServer);
|
|
|
|
|
|
|
|
clicker.sendPluginMessage(CitizensAPI.getPlugin(), "BungeeCord", out.toByteArray());
|
2020-04-30 17:45:06 +02:00
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
clicker.chat("/" + interpolatedCommand);
|
|
|
|
} catch (Throwable t) {
|
|
|
|
t.printStackTrace();
|
|
|
|
}
|
2020-04-30 15:15:24 +02:00
|
|
|
}
|
2020-04-30 18:40:27 +02:00
|
|
|
|
2020-04-30 15:15:24 +02:00
|
|
|
if (op) {
|
|
|
|
clicker.setOp(wasOp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class NPCCommandBuilder {
|
|
|
|
String command;
|
|
|
|
int cooldown;
|
|
|
|
int delay;
|
|
|
|
Hand hand;
|
|
|
|
int n = -1;
|
|
|
|
boolean op;
|
|
|
|
List<String> perms = Lists.newArrayList();
|
|
|
|
boolean player;
|
|
|
|
|
|
|
|
public NPCCommandBuilder(String command, Hand hand) {
|
|
|
|
this.command = command;
|
|
|
|
this.hand = hand;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder addPerm(String permission) {
|
|
|
|
this.perms.add(permission);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder addPerms(List<String> perms) {
|
|
|
|
this.perms.addAll(perms);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private NPCCommand build(String id) {
|
|
|
|
return new NPCCommand(id, command, hand, player, op, cooldown, perms, n, delay);
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder command(String command) {
|
|
|
|
this.command = command;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder cooldown(int cooldown) {
|
|
|
|
this.cooldown = cooldown;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder delay(int delay) {
|
|
|
|
this.delay = delay;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder n(int n) {
|
|
|
|
this.n = n;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder op(boolean op) {
|
|
|
|
this.op = op;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public NPCCommandBuilder player(boolean player) {
|
|
|
|
this.player = player;
|
|
|
|
return this;
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class NPCCommandPersister implements Persister<NPCCommand> {
|
|
|
|
public NPCCommandPersister() {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public NPCCommand create(DataKey root) {
|
2020-03-02 16:40:13 +01:00
|
|
|
List<String> perms = Lists.newArrayList();
|
|
|
|
for (DataKey key : root.getRelative("permissions").getIntegerSubKeys()) {
|
|
|
|
perms.add(key.getString(""));
|
|
|
|
}
|
2019-12-02 04:27:15 +01:00
|
|
|
return new NPCCommand(root.name(), root.getString("command"), Hand.valueOf(root.getString("hand")),
|
2020-02-22 05:57:03 +01:00
|
|
|
Boolean.valueOf(root.getString("player")), Boolean.valueOf(root.getString("op")),
|
2020-04-30 15:15:24 +02:00
|
|
|
root.getInt("cooldown"), perms, root.getInt("n"), root.getInt("delay"));
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void save(NPCCommand instance, DataKey root) {
|
|
|
|
root.setString("command", instance.command);
|
|
|
|
root.setString("hand", instance.hand.name());
|
2019-12-02 04:27:15 +01:00
|
|
|
root.setBoolean("player", instance.player);
|
2019-12-29 14:14:38 +01:00
|
|
|
root.setBoolean("op", instance.op);
|
2020-02-22 05:57:03 +01:00
|
|
|
root.setInt("cooldown", instance.cooldown);
|
2020-03-03 16:40:42 +01:00
|
|
|
root.setInt("n", instance.n);
|
2020-04-30 15:15:24 +02:00
|
|
|
root.setInt("delay", instance.delay);
|
2020-03-02 16:40:13 +01:00
|
|
|
for (int i = 0; i < instance.perms.size(); i++) {
|
|
|
|
root.setString("permissions." + i, instance.perms.get(i));
|
|
|
|
}
|
2020-02-22 05:57:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class PlayerNPCCommand {
|
2020-04-26 06:53:00 +02:00
|
|
|
@Persist(valueType = Long.class)
|
2020-02-22 05:57:03 +01:00
|
|
|
Map<String, Long> lastUsed = Maps.newHashMap();
|
2020-03-03 16:40:42 +01:00
|
|
|
@Persist
|
|
|
|
Map<String, Integer> nUsed = Maps.newHashMap();
|
2020-02-22 05:57:03 +01:00
|
|
|
|
|
|
|
public PlayerNPCCommand() {
|
|
|
|
}
|
|
|
|
|
2020-03-02 16:40:13 +01:00
|
|
|
public boolean canUse(Player player, NPCCommand command) {
|
|
|
|
for (String perm : command.perms) {
|
2020-03-03 16:31:04 +01:00
|
|
|
if (!player.hasPermission(perm)) {
|
2020-03-02 16:40:13 +01:00
|
|
|
return false;
|
2020-03-03 16:31:04 +01:00
|
|
|
}
|
2020-03-02 16:40:13 +01:00
|
|
|
}
|
2020-02-22 05:57:03 +01:00
|
|
|
long currentTimeSec = System.currentTimeMillis() / 1000;
|
|
|
|
if (lastUsed.containsKey(command.command)) {
|
2020-04-26 06:53:00 +02:00
|
|
|
if (currentTimeSec < lastUsed.get(command.command) + command.cooldown) {
|
2020-02-22 05:57:03 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
lastUsed.remove(command.command);
|
|
|
|
}
|
2020-03-03 16:40:42 +01:00
|
|
|
int previouslyUsed = nUsed.getOrDefault(command.command, 0);
|
|
|
|
if (command.n > 0 && command.n <= previouslyUsed) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-02-22 05:57:03 +01:00
|
|
|
if (command.cooldown > 0) {
|
|
|
|
lastUsed.put(command.command, currentTimeSec);
|
|
|
|
}
|
2020-03-03 16:40:42 +01:00
|
|
|
if (command.n > 0) {
|
|
|
|
nUsed.put(command.command, previouslyUsed + 1);
|
|
|
|
}
|
2020-02-22 05:57:03 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static class PlayerNPCCommandPersister implements Persister<PlayerNPCCommand> {
|
|
|
|
public PlayerNPCCommandPersister() {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public PlayerNPCCommand create(DataKey root) {
|
|
|
|
return PersistenceLoader.load(PlayerNPCCommand.class, root);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void save(PlayerNPCCommand instance, DataKey root) {
|
|
|
|
PersistenceLoader.save(instance, root);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|