2017-12-30 08:36:36 +01:00
|
|
|
package net.citizensnpcs.commands;
|
|
|
|
|
2023-03-28 19:28:08 +02:00
|
|
|
import java.io.File;
|
2023-08-13 19:31:34 +02:00
|
|
|
import java.io.FileOutputStream;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.nio.channels.Channels;
|
|
|
|
import java.nio.channels.ReadableByteChannel;
|
2023-03-28 19:28:08 +02:00
|
|
|
import java.nio.file.Files;
|
2023-03-12 15:29:41 +01:00
|
|
|
import java.time.Duration;
|
2017-12-30 08:36:36 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collections;
|
2022-09-08 23:43:25 +02:00
|
|
|
import java.util.Iterator;
|
2017-12-30 08:36:36 +01:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.UUID;
|
2023-03-14 13:55:33 +01:00
|
|
|
import java.util.stream.Collectors;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2023-04-07 20:35:55 +02:00
|
|
|
import org.bukkit.Art;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.ChatColor;
|
|
|
|
import org.bukkit.DyeColor;
|
|
|
|
import org.bukkit.GameMode;
|
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
2018-10-06 12:31:16 +02:00
|
|
|
import org.bukkit.OfflinePlayer;
|
2023-06-19 14:55:16 +02:00
|
|
|
import org.bukkit.Sound;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.World;
|
2020-08-03 14:30:50 +02:00
|
|
|
import org.bukkit.block.Block;
|
2020-08-10 12:02:35 +02:00
|
|
|
import org.bukkit.block.BlockFace;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.command.CommandSender;
|
|
|
|
import org.bukkit.command.ConsoleCommandSender;
|
|
|
|
import org.bukkit.entity.Ageable;
|
2022-09-07 21:01:39 +02:00
|
|
|
import org.bukkit.entity.ArmorStand;
|
2022-05-06 15:25:12 +02:00
|
|
|
import org.bukkit.entity.Damageable;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.entity.Entity;
|
|
|
|
import org.bukkit.entity.EntityType;
|
2020-09-14 11:57:58 +02:00
|
|
|
import org.bukkit.entity.Horse;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.entity.Ocelot;
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
import org.bukkit.entity.Rabbit;
|
|
|
|
import org.bukkit.entity.Villager.Profession;
|
|
|
|
import org.bukkit.entity.Zombie;
|
|
|
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
2023-11-04 19:03:57 +01:00
|
|
|
import org.bukkit.inventory.InventoryHolder;
|
2022-07-15 04:21:44 +02:00
|
|
|
import org.bukkit.inventory.ItemStack;
|
2023-11-04 19:03:57 +01:00
|
|
|
import org.bukkit.inventory.meta.SkullMeta;
|
2020-03-20 10:29:23 +01:00
|
|
|
import org.json.simple.JSONObject;
|
2023-08-13 19:31:34 +02:00
|
|
|
import org.json.simple.parser.JSONParser;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
import com.google.common.base.Joiner;
|
|
|
|
import com.google.common.base.Splitter;
|
2021-04-17 15:34:46 +02:00
|
|
|
import com.google.common.base.Strings;
|
2017-12-30 08:36:36 +01:00
|
|
|
import com.google.common.collect.Iterables;
|
|
|
|
import com.google.common.collect.Lists;
|
2023-08-13 19:31:34 +02:00
|
|
|
import com.google.common.io.BaseEncoding;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
import net.citizensnpcs.Citizens;
|
2023-12-21 19:21:18 +01:00
|
|
|
import net.citizensnpcs.ProtocolLibListener;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.Settings.Setting;
|
2022-12-18 18:44:16 +01:00
|
|
|
import net.citizensnpcs.StoredShops;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.CitizensAPI;
|
|
|
|
import net.citizensnpcs.api.ai.speech.SpeechContext;
|
2022-05-31 16:47:00 +02:00
|
|
|
import net.citizensnpcs.api.ai.tree.StatusMapper;
|
2022-09-07 21:01:39 +02:00
|
|
|
import net.citizensnpcs.api.command.Arg;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.command.Command;
|
|
|
|
import net.citizensnpcs.api.command.CommandContext;
|
|
|
|
import net.citizensnpcs.api.command.CommandMessages;
|
2022-09-06 20:11:07 +02:00
|
|
|
import net.citizensnpcs.api.command.Flag;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.command.Requirements;
|
|
|
|
import net.citizensnpcs.api.command.exception.CommandException;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.api.command.exception.CommandUsageException;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.command.exception.NoPermissionsException;
|
2018-07-19 14:18:47 +02:00
|
|
|
import net.citizensnpcs.api.command.exception.RequirementMissingException;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.command.exception.ServerCommandException;
|
2019-04-23 16:39:51 +02:00
|
|
|
import net.citizensnpcs.api.event.CommandSenderCloneNPCEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.CommandSenderCreateNPCEvent;
|
|
|
|
import net.citizensnpcs.api.event.DespawnReason;
|
2021-04-13 06:06:22 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCTeleportEvent;
|
2019-04-23 16:39:51 +02:00
|
|
|
import net.citizensnpcs.api.event.PlayerCloneNPCEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.PlayerCreateNPCEvent;
|
2018-08-08 10:08:38 +02:00
|
|
|
import net.citizensnpcs.api.event.SpawnReason;
|
2021-02-01 15:35:28 +01:00
|
|
|
import net.citizensnpcs.api.gui.InventoryMenu;
|
2022-02-19 18:05:38 +01:00
|
|
|
import net.citizensnpcs.api.npc.BlockBreaker;
|
|
|
|
import net.citizensnpcs.api.npc.BlockBreaker.BlockBreakerConfiguration;
|
2021-02-27 07:41:05 +01:00
|
|
|
import net.citizensnpcs.api.npc.MemoryNPCDataStore;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
2023-01-01 08:26:35 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPC.NPCUpdate;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPCRegistry;
|
|
|
|
import net.citizensnpcs.api.trait.Trait;
|
2023-06-18 11:23:55 +02:00
|
|
|
import net.citizensnpcs.api.trait.trait.Equipment;
|
|
|
|
import net.citizensnpcs.api.trait.trait.Equipment.EquipmentSlot;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.trait.trait.Inventory;
|
|
|
|
import net.citizensnpcs.api.trait.trait.MobType;
|
|
|
|
import net.citizensnpcs.api.trait.trait.Owner;
|
2023-03-07 16:58:03 +01:00
|
|
|
import net.citizensnpcs.api.trait.trait.PlayerFilter;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.trait.trait.Spawned;
|
2023-01-03 13:55:27 +01:00
|
|
|
import net.citizensnpcs.api.util.EntityDim;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.util.Messaging;
|
|
|
|
import net.citizensnpcs.api.util.Paginator;
|
2022-10-26 10:59:11 +02:00
|
|
|
import net.citizensnpcs.api.util.Placeholders;
|
2020-05-15 06:26:21 +02:00
|
|
|
import net.citizensnpcs.api.util.SpigotUtil;
|
2021-05-07 19:55:53 +02:00
|
|
|
import net.citizensnpcs.commands.gui.NPCConfigurator;
|
2022-02-19 07:36:45 +01:00
|
|
|
import net.citizensnpcs.commands.history.CommandHistory;
|
2022-02-19 06:35:16 +01:00
|
|
|
import net.citizensnpcs.commands.history.CreateNPCHistoryItem;
|
2023-08-27 19:49:14 +02:00
|
|
|
import net.citizensnpcs.commands.history.RemoveNPCHistoryItem;
|
2023-09-20 16:05:05 +02:00
|
|
|
import net.citizensnpcs.editor.Editor;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.npc.EntityControllers;
|
|
|
|
import net.citizensnpcs.npc.NPCSelector;
|
|
|
|
import net.citizensnpcs.npc.Template;
|
|
|
|
import net.citizensnpcs.trait.Age;
|
|
|
|
import net.citizensnpcs.trait.Anchors;
|
|
|
|
import net.citizensnpcs.trait.ArmorStandTrait;
|
2023-01-03 13:55:27 +01:00
|
|
|
import net.citizensnpcs.trait.BoundingBoxTrait;
|
2021-02-02 15:33:06 +01:00
|
|
|
import net.citizensnpcs.trait.ClickRedirectTrait;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.trait.CommandTrait;
|
2022-10-24 16:01:40 +02:00
|
|
|
import net.citizensnpcs.trait.CommandTrait.CommandTraitError;
|
2020-07-03 16:59:18 +02:00
|
|
|
import net.citizensnpcs.trait.CommandTrait.ExecutionMode;
|
2021-02-01 15:35:28 +01:00
|
|
|
import net.citizensnpcs.trait.CommandTrait.ItemRequirementGUI;
|
2020-04-30 15:15:24 +02:00
|
|
|
import net.citizensnpcs.trait.CommandTrait.NPCCommandBuilder;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.Controllable;
|
|
|
|
import net.citizensnpcs.trait.CurrentLocation;
|
2021-02-07 11:45:10 +01:00
|
|
|
import net.citizensnpcs.trait.DropsTrait;
|
2021-02-18 16:29:15 +01:00
|
|
|
import net.citizensnpcs.trait.EnderCrystalTrait;
|
2020-06-27 09:41:47 +02:00
|
|
|
import net.citizensnpcs.trait.EndermanTrait;
|
2018-10-06 11:11:57 +02:00
|
|
|
import net.citizensnpcs.trait.FollowTrait;
|
2018-11-12 07:53:52 +01:00
|
|
|
import net.citizensnpcs.trait.GameModeTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.Gravity;
|
2020-06-30 12:17:14 +02:00
|
|
|
import net.citizensnpcs.trait.HologramTrait;
|
2023-02-05 17:40:01 +01:00
|
|
|
import net.citizensnpcs.trait.HomeTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.HorseModifiers;
|
|
|
|
import net.citizensnpcs.trait.LookClose;
|
2022-12-24 18:37:54 +01:00
|
|
|
import net.citizensnpcs.trait.MirrorTrait;
|
2019-03-01 13:50:44 +01:00
|
|
|
import net.citizensnpcs.trait.MountTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.OcelotModifiers;
|
2023-01-26 18:54:13 +01:00
|
|
|
import net.citizensnpcs.trait.PacketNPC;
|
2023-04-07 20:35:55 +02:00
|
|
|
import net.citizensnpcs.trait.PaintingTrait;
|
2023-02-21 16:59:33 +01:00
|
|
|
import net.citizensnpcs.trait.PausePathfindingTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.Poses;
|
|
|
|
import net.citizensnpcs.trait.Powered;
|
|
|
|
import net.citizensnpcs.trait.RabbitType;
|
2022-12-03 11:21:46 +01:00
|
|
|
import net.citizensnpcs.trait.RotationTrait;
|
2019-07-12 09:39:38 +02:00
|
|
|
import net.citizensnpcs.trait.ScoreboardTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.SheepTrait;
|
2021-07-14 15:23:55 +02:00
|
|
|
import net.citizensnpcs.trait.ShopTrait;
|
|
|
|
import net.citizensnpcs.trait.ShopTrait.NPCShop;
|
2023-06-08 16:37:50 +02:00
|
|
|
import net.citizensnpcs.trait.SitTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.SkinLayers;
|
|
|
|
import net.citizensnpcs.trait.SkinLayers.Layer;
|
2020-04-18 20:07:03 +02:00
|
|
|
import net.citizensnpcs.trait.SkinTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.SlimeSize;
|
|
|
|
import net.citizensnpcs.trait.VillagerProfession;
|
|
|
|
import net.citizensnpcs.trait.WitherTrait;
|
|
|
|
import net.citizensnpcs.trait.WolfModifiers;
|
2022-10-08 05:11:40 +02:00
|
|
|
import net.citizensnpcs.trait.waypoint.Waypoints;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.util.Anchor;
|
|
|
|
import net.citizensnpcs.util.Messages;
|
2023-03-28 19:28:08 +02:00
|
|
|
import net.citizensnpcs.util.MojangSkinGenerator;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.util.NMS;
|
2022-04-19 09:50:52 +02:00
|
|
|
import net.citizensnpcs.util.PlayerAnimation;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.util.StringHelper;
|
|
|
|
import net.citizensnpcs.util.Util;
|
|
|
|
|
|
|
|
@Requirements(selected = true, ownership = true)
|
|
|
|
public class NPCCommands {
|
2022-02-19 07:36:45 +01:00
|
|
|
private final CommandHistory history;
|
2023-12-21 19:21:18 +01:00
|
|
|
private final ProtocolLibListener protocolListener;
|
2017-12-30 08:36:36 +01:00
|
|
|
private final NPCSelector selector;
|
2022-12-18 18:44:16 +01:00
|
|
|
private final StoredShops shops;
|
2021-02-27 07:41:05 +01:00
|
|
|
private final NPCRegistry temporaryRegistry;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
public NPCCommands(Citizens plugin) {
|
|
|
|
selector = plugin.getNPCSelector();
|
2022-12-18 18:44:16 +01:00
|
|
|
shops = plugin.getShops();
|
2021-02-27 07:41:05 +01:00
|
|
|
temporaryRegistry = CitizensAPI.createCitizensBackedNPCRegistry(new MemoryNPCDataStore());
|
2022-02-19 07:36:45 +01:00
|
|
|
history = new CommandHistory(selector);
|
2023-12-21 19:21:18 +01:00
|
|
|
protocolListener = plugin.getProtocolLibListener();
|
2022-02-19 06:35:16 +01:00
|
|
|
}
|
|
|
|
|
2022-12-18 17:36:53 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "activationrange [range]",
|
|
|
|
desc = "Sets the activation range",
|
|
|
|
modifiers = { "activationrange" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.activationrange")
|
|
|
|
public void activationrange(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Integer range) {
|
|
|
|
if (range == null) {
|
|
|
|
npc.data().remove(NPC.Metadata.ACTIVATION_RANGE);
|
|
|
|
} else {
|
|
|
|
npc.data().setPersistent(NPC.Metadata.ACTIVATION_RANGE, range);
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.ACTIVATION_RANGE_SET, range);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-07 21:01:39 +02:00
|
|
|
usage = "age [age] (-l(ock))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Set the age of a NPC",
|
|
|
|
help = Messages.COMMAND_AGE_HELP,
|
|
|
|
flags = "l",
|
|
|
|
modifiers = { "age" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.age")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void age(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!npc.isSpawned() || !(npc.getEntity() instanceof Ageable) && !(npc.getEntity() instanceof Zombie)
|
|
|
|
&& !npc.getEntity().getType().name().equals("TADPOLE"))
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.MOBTYPE_CANNOT_BE_AGED, npc.getName());
|
2020-09-14 11:57:58 +02:00
|
|
|
Age trait = npc.getOrAddTrait(Age.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
boolean toggleLock = args.hasFlag('l');
|
|
|
|
if (toggleLock) {
|
|
|
|
Messaging.sendTr(sender, trait.toggle() ? Messages.AGE_LOCKED : Messages.AGE_UNLOCKED);
|
|
|
|
}
|
|
|
|
if (args.argsLength() <= 1) {
|
2022-04-23 07:42:48 +02:00
|
|
|
if (!toggleLock) {
|
2017-12-30 08:36:36 +01:00
|
|
|
trait.describe(sender);
|
2022-04-23 07:42:48 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
int age = 0;
|
|
|
|
try {
|
|
|
|
age = args.getInteger(1);
|
2022-04-23 07:42:48 +02:00
|
|
|
if (age > 0)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_AGE);
|
2022-04-23 07:42:48 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.AGE_SET_NORMAL, npc.getName(), age);
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
if (args.getString(1).equalsIgnoreCase("baby")) {
|
|
|
|
age = -24000;
|
|
|
|
Messaging.sendTr(sender, Messages.AGE_SET_BABY, npc.getName());
|
|
|
|
} else if (args.getString(1).equalsIgnoreCase("adult")) {
|
|
|
|
age = 0;
|
|
|
|
Messaging.sendTr(sender, Messages.AGE_SET_ADULT, npc.getName());
|
|
|
|
} else
|
|
|
|
throw new CommandException(Messages.INVALID_AGE);
|
|
|
|
}
|
|
|
|
trait.setAge(age);
|
|
|
|
}
|
|
|
|
|
2023-01-16 16:54:21 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "aggressive [true|false]",
|
|
|
|
desc = "Sets the aggressive status of the entity",
|
|
|
|
modifiers = { "aggressive" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.aggressive")
|
|
|
|
public void aggressive(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Boolean aggressive) {
|
|
|
|
boolean aggro = aggressive != null ? aggressive : !npc.data().get(NPC.Metadata.AGGRESSIVE, false);
|
|
|
|
npc.data().set(NPC.Metadata.AGGRESSIVE, aggro);
|
|
|
|
NMS.setAggressive(npc.getEntity(), aggro);
|
|
|
|
}
|
|
|
|
|
2020-10-05 09:59:14 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "ai (true|false)",
|
|
|
|
desc = "Sets whether the NPC should use vanilla AI",
|
|
|
|
modifiers = { "ai" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.ai")
|
2022-09-07 21:01:39 +02:00
|
|
|
public void ai(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Boolean explicit)
|
|
|
|
throws CommandException {
|
|
|
|
boolean useAI = explicit == null ? !npc.useMinecraftAI() : explicit;
|
2020-10-05 09:59:14 +02:00
|
|
|
npc.setUseMinecraftAI(useAI);
|
|
|
|
Messaging.sendTr(sender, useAI ? Messages.USING_MINECRAFT_AI : Messages.NOT_USING_MINECRAFT_AI);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-06 20:11:07 +02:00
|
|
|
usage = "anchor (--save [name]|--assume [name]|--remove [name]) (-a) (-c)",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Changes/Saves/Lists NPC's location anchor(s)",
|
|
|
|
flags = "ac",
|
|
|
|
modifiers = { "anchor" },
|
|
|
|
min = 1,
|
|
|
|
max = 3,
|
|
|
|
permission = "citizens.npc.anchor")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void anchor(CommandContext args, CommandSender sender, NPC npc, @Flag("save") String save,
|
|
|
|
@Flag("assume") String assume, @Flag("remove") String remove) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
Anchors trait = npc.getOrAddTrait(Anchors.class);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (save != null) {
|
|
|
|
if (save.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_ANCHOR_NAME);
|
|
|
|
|
|
|
|
if (args.getSenderLocation() == null)
|
|
|
|
throw new ServerCommandException();
|
|
|
|
|
|
|
|
if (args.hasFlag('c')) {
|
2022-09-06 20:11:07 +02:00
|
|
|
if (trait.addAnchor(save, args.getSenderTargetBlockLocation())) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.ANCHOR_ADDED);
|
|
|
|
} else
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.ANCHOR_ALREADY_EXISTS, save);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else if (trait.addAnchor(save, args.getSenderLocation())) {
|
|
|
|
Messaging.sendTr(sender, Messages.ANCHOR_ADDED);
|
|
|
|
} else
|
|
|
|
throw new CommandException(Messages.ANCHOR_ALREADY_EXISTS, save);
|
2022-09-06 20:11:07 +02:00
|
|
|
} else if (assume != null) {
|
|
|
|
if (assume.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_ANCHOR_NAME);
|
|
|
|
|
2022-09-06 20:11:07 +02:00
|
|
|
Anchor anchor = trait.getAnchor(assume);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (anchor == null)
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.ANCHOR_MISSING, assume);
|
2017-12-30 08:36:36 +01:00
|
|
|
npc.teleport(anchor.getLocation(), TeleportCause.COMMAND);
|
2022-09-06 20:11:07 +02:00
|
|
|
} else if (remove != null) {
|
|
|
|
if (remove.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_ANCHOR_NAME);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (trait.removeAnchor(trait.getAnchor(remove))) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.ANCHOR_REMOVED);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.ANCHOR_MISSING, remove);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else if (!args.hasFlag('a')) {
|
2019-09-24 16:05:10 +02:00
|
|
|
Paginator paginator = new Paginator().header("Anchors").console(sender instanceof ConsoleCommandSender);
|
2022-10-05 16:27:09 +02:00
|
|
|
paginator.addLine("Key: [[ID]] <blue>Name <red>World <gray>Location (X,Y,Z)");
|
2017-12-30 08:36:36 +01:00
|
|
|
for (int i = 0; i < trait.getAnchors().size(); i++) {
|
|
|
|
if (trait.getAnchors().get(i).isLoaded()) {
|
2022-10-05 16:27:09 +02:00
|
|
|
String line = i + "<blue> " + trait.getAnchors().get(i).getName() + "<yellow> "
|
|
|
|
+ trait.getAnchors().get(i).getLocation().getWorld().getName() + "<gray> "
|
2017-12-30 08:36:36 +01:00
|
|
|
+ trait.getAnchors().get(i).getLocation().getBlockX() + ", "
|
|
|
|
+ trait.getAnchors().get(i).getLocation().getBlockY() + ", "
|
|
|
|
+ trait.getAnchors().get(i).getLocation().getBlockZ();
|
|
|
|
paginator.addLine(line);
|
|
|
|
} else {
|
|
|
|
String[] parts = trait.getAnchors().get(i).getUnloadedValue();
|
2022-10-05 16:27:09 +02:00
|
|
|
String line = i + "<blue> " + trait.getAnchors().get(i).getName() + "<red> " + parts[0]
|
|
|
|
+ "<gray> " + parts[1] + ", " + parts[2] + ", " + parts[3] + " <white>(unloaded)";
|
2017-12-30 08:36:36 +01:00
|
|
|
paginator.addLine(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int page = args.getInteger(1, 1);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!paginator.sendPage(sender, page))
|
2022-07-09 19:17:26 +02:00
|
|
|
throw new CommandException(Messages.COMMAND_PAGE_MISSING, page);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
// Assume Player's position
|
|
|
|
if (!args.hasFlag('a'))
|
|
|
|
return;
|
|
|
|
if (sender instanceof ConsoleCommandSender)
|
|
|
|
throw new ServerCommandException();
|
|
|
|
npc.teleport(args.getSenderLocation(), TeleportCause.COMMAND);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-07 21:01:39 +02:00
|
|
|
usage = "armorstand --visible [visible] --small [small] --gravity [gravity] --arms [arms] --baseplate [baseplate] --(body|leftarm|leftleg|rightarm|rightleg)pose [angle x,y,z]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Edit armorstand properties",
|
|
|
|
modifiers = { "armorstand" },
|
|
|
|
min = 1,
|
2022-02-19 18:05:38 +01:00
|
|
|
max = 1,
|
2022-09-07 21:01:39 +02:00
|
|
|
valueFlags = { "bodypose", "leftarmpose", "rightarmpose", "leftlegpose", "rightlegpose" },
|
2022-02-19 18:05:38 +01:00
|
|
|
permission = "citizens.npc.armorstand")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = EntityType.ARMOR_STAND)
|
2022-09-06 20:11:07 +02:00
|
|
|
public void armorstand(CommandContext args, CommandSender sender, NPC npc, @Flag("visible") Boolean visible,
|
|
|
|
@Flag("small") Boolean small, @Flag("gravity") Boolean gravity, @Flag("arms") Boolean arms,
|
|
|
|
@Flag("baseplate") Boolean baseplate) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
ArmorStandTrait trait = npc.getOrAddTrait(ArmorStandTrait.class);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (visible != null) {
|
|
|
|
trait.setVisible(visible);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (small != null) {
|
|
|
|
trait.setSmall(small);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (gravity != null) {
|
|
|
|
trait.setGravity(gravity);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (arms != null) {
|
|
|
|
trait.setHasArms(arms);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (baseplate != null) {
|
|
|
|
trait.setHasBaseplate(baseplate);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-07 21:01:39 +02:00
|
|
|
ArmorStand ent = (ArmorStand) npc.getEntity();
|
|
|
|
if (args.hasValueFlag("bodypose")) {
|
|
|
|
ent.setBodyPose(args.parseEulerAngle(args.getFlag("bodypose")));
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("leftarmpose")) {
|
|
|
|
ent.setLeftArmPose(args.parseEulerAngle(args.getFlag("leftarmpose")));
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("leftlegpose")) {
|
|
|
|
ent.setLeftLegPose(args.parseEulerAngle(args.getFlag("leftlegpose")));
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("rightarmpose")) {
|
|
|
|
ent.setRightArmPose(args.parseEulerAngle(args.getFlag("rightarmpose")));
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("rightlegpose")) {
|
|
|
|
ent.setRightLegPose(args.parseEulerAngle(args.getFlag("rightlegpose")));
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-02-19 18:05:38 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "breakblock --location [x,y,z] --radius [radius]",
|
|
|
|
desc = "Mine a block at the given location or cursor if not specified",
|
|
|
|
modifiers = { "breakblock" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2022-09-06 20:11:07 +02:00
|
|
|
valueFlags = "location",
|
2022-02-19 18:05:38 +01:00
|
|
|
permission = "citizens.npc.breakblock")
|
|
|
|
@Requirements(selected = true, ownership = true, livingEntity = true)
|
2022-09-06 20:11:07 +02:00
|
|
|
public void breakblock(CommandContext args, CommandSender sender, NPC npc, @Flag("radius") Double radius)
|
|
|
|
throws CommandException {
|
2022-02-19 18:05:38 +01:00
|
|
|
BlockBreakerConfiguration cfg = new BlockBreakerConfiguration();
|
2022-09-06 20:11:07 +02:00
|
|
|
if (radius != null) {
|
|
|
|
cfg.radius(radius);
|
2022-09-03 09:39:08 +02:00
|
|
|
} else if (Setting.DEFAULT_BLOCK_BREAKER_RADIUS.asDouble() > 0) {
|
|
|
|
cfg.radius(Setting.DEFAULT_BLOCK_BREAKER_RADIUS.asDouble());
|
2022-02-19 18:05:38 +01:00
|
|
|
}
|
2023-11-04 19:03:57 +01:00
|
|
|
if (npc.getEntity() instanceof InventoryHolder) {
|
|
|
|
cfg.blockBreaker((block, itemstack) -> {
|
|
|
|
org.bukkit.inventory.Inventory inventory = ((InventoryHolder) npc.getEntity()).getInventory();
|
|
|
|
Location location = npc.getEntity().getLocation();
|
|
|
|
for (ItemStack drop : block.getDrops(itemstack)) {
|
|
|
|
for (ItemStack unadded : inventory.addItem(drop).values()) {
|
|
|
|
location.getWorld().dropItemNaturally(npc.getEntity().getLocation(), unadded);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2022-02-19 18:05:38 +01:00
|
|
|
BlockBreaker breaker = npc.getBlockBreaker(args.getSenderTargetBlockLocation().getBlock(), cfg);
|
2022-05-31 16:47:00 +02:00
|
|
|
npc.getDefaultGoalController().addBehavior(StatusMapper.singleUse(breaker), 1);
|
2022-02-19 18:05:38 +01:00
|
|
|
}
|
|
|
|
|
2021-05-06 19:46:59 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2021-10-10 17:19:43 +02:00
|
|
|
usage = "chunkload (-t(emporary))",
|
2021-05-06 19:46:59 +02:00
|
|
|
desc = "Toggle the NPC forcing chunks to stay loaded",
|
|
|
|
modifiers = { "chunkload", "cload" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2021-10-10 17:19:43 +02:00
|
|
|
flags = "t",
|
2021-05-06 19:46:59 +02:00
|
|
|
permission = "citizens.npc.chunkload")
|
|
|
|
@Requirements(selected = true, ownership = true)
|
|
|
|
public void chunkload(CommandContext args, CommandSender sender, NPC npc) {
|
2023-01-01 08:26:35 +01:00
|
|
|
boolean enabled = !npc.data().get(NPC.Metadata.KEEP_CHUNK_LOADED, Setting.KEEP_CHUNKS_LOADED.asBoolean());
|
2021-10-10 17:19:43 +02:00
|
|
|
if (args.hasFlag('t')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().set(NPC.Metadata.KEEP_CHUNK_LOADED, enabled);
|
2021-10-10 17:19:43 +02:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.KEEP_CHUNK_LOADED, enabled);
|
2021-10-10 17:19:43 +02:00
|
|
|
}
|
2021-05-06 19:46:59 +02:00
|
|
|
Messaging.sendTr(sender, enabled ? Messages.CHUNKLOAD_SET : Messages.CHUNKLOAD_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "collidable",
|
|
|
|
desc = "Toggles an NPC's collidability",
|
2022-01-16 07:05:23 +01:00
|
|
|
modifiers = { "collidable", "pushable" },
|
2020-02-14 15:48:40 +01:00
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.collidable")
|
2022-01-16 07:05:23 +01:00
|
|
|
@Requirements(ownership = true, selected = true)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void collidable(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2023-04-25 16:23:41 +02:00
|
|
|
npc.data().setPersistent(NPC.Metadata.COLLIDABLE, !npc.data().get(NPC.Metadata.COLLIDABLE, !npc.isProtected()));
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender,
|
2022-11-16 14:58:05 +01:00
|
|
|
npc.data().<Boolean> get(NPC.Metadata.COLLIDABLE) ? Messages.COLLIDABLE_SET : Messages.COLLIDABLE_UNSET,
|
2017-12-30 08:36:36 +01:00
|
|
|
npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-06-25 07:41:19 +02:00
|
|
|
usage = "command|cmd (add [command] | remove [id] | permissions [permissions] | sequential | random | clearerror [type] (name|uuid) | errormsg [type] [msg] | persistsequence [true|false] | cost [cost] (id) | expcost [cost] (id) | itemcost (id)) (-s(hift)) (-l[eft]/-r[ight]) (-p[layer] -o[p]), --cooldown --gcooldown [seconds] --delay [ticks] --permissions [perms] --n [max # of uses]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Controls commands which will be run when clicking on an NPC",
|
2020-06-11 10:47:55 +02:00
|
|
|
help = Messages.NPC_COMMAND_HELP,
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "command", "cmd" },
|
|
|
|
min = 1,
|
2022-11-28 16:10:50 +01:00
|
|
|
flags = "lrpos",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.command")
|
2022-12-29 16:26:02 +01:00
|
|
|
public void command(CommandContext args, CommandSender sender, NPC npc,
|
|
|
|
@Flag(value = { "permissions", "permission" }) String permissions,
|
2023-03-12 15:29:41 +01:00
|
|
|
@Flag(value = "cooldown", defValue = "0") Duration cooldown,
|
|
|
|
@Flag(value = "gcooldown", defValue = "0") Duration gcooldown, @Flag(value = "n", defValue = "-1") int n,
|
|
|
|
@Flag(value = "delay", defValue = "0") Duration delay,
|
2022-09-07 21:01:39 +02:00
|
|
|
@Arg(
|
|
|
|
value = 1,
|
2022-11-28 16:10:50 +01:00
|
|
|
completions = { "add", "remove", "permissions", "persistsequence", "sequential", "random",
|
2023-06-25 07:41:19 +02:00
|
|
|
"hideerrors", "errormsg", "clearerror", "expcost", "itemcost", "cost" }) String action)
|
2022-09-07 21:01:39 +02:00
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
CommandTrait commands = npc.getOrAddTrait(CommandTrait.class);
|
2019-09-23 14:29:31 +02:00
|
|
|
if (args.argsLength() == 1) {
|
|
|
|
commands.describe(sender);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("add")) {
|
2019-09-23 14:29:31 +02:00
|
|
|
if (args.argsLength() == 2)
|
|
|
|
throw new CommandUsageException();
|
2023-10-01 11:27:38 +02:00
|
|
|
|
2022-09-14 20:35:42 +02:00
|
|
|
if (args.hasFlag('o') && !sender.hasPermission("citizens.admin"))
|
|
|
|
throw new NoPermissionsException();
|
2023-10-01 11:27:38 +02:00
|
|
|
|
2019-09-23 14:29:31 +02:00
|
|
|
String command = args.getJoinedStrings(2);
|
2020-01-17 10:11:23 +01:00
|
|
|
CommandTrait.Hand hand = args.hasFlag('l') && args.hasFlag('r') ? CommandTrait.Hand.BOTH
|
|
|
|
: args.hasFlag('l') ? CommandTrait.Hand.LEFT : CommandTrait.Hand.RIGHT;
|
2022-11-28 16:10:50 +01:00
|
|
|
if (args.hasFlag('s') && hand != CommandTrait.Hand.BOTH) {
|
|
|
|
hand = hand == CommandTrait.Hand.LEFT ? CommandTrait.Hand.SHIFT_LEFT : CommandTrait.Hand.SHIFT_RIGHT;
|
|
|
|
}
|
2020-03-02 16:40:13 +01:00
|
|
|
List<String> perms = Lists.newArrayList();
|
2022-09-06 20:11:07 +02:00
|
|
|
if (permissions != null) {
|
|
|
|
perms.addAll(Arrays.asList(permissions.split(",")));
|
2020-03-02 16:40:13 +01:00
|
|
|
}
|
2023-10-01 11:27:38 +02:00
|
|
|
if (command.toLowerCase().startsWith("npc select"))
|
2022-12-27 12:57:48 +01:00
|
|
|
throw new CommandException("npc select not currently supported within commands. Use --id <id> instead");
|
2023-10-01 11:27:38 +02:00
|
|
|
|
2022-04-29 20:39:26 +02:00
|
|
|
try {
|
|
|
|
int id = commands.addCommand(new NPCCommandBuilder(command, hand).addPerms(perms)
|
2022-09-06 20:11:07 +02:00
|
|
|
.player(args.hasFlag('p') || args.hasFlag('o')).op(args.hasFlag('o')).cooldown(cooldown)
|
2023-10-13 15:49:21 +02:00
|
|
|
.globalCooldown(gcooldown).n(n).delay(delay));
|
2022-04-29 20:39:26 +02:00
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_ADDED, command, id);
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
throw new CommandException(CommandMessages.INVALID_NUMBER);
|
|
|
|
}
|
2022-10-24 16:01:40 +02:00
|
|
|
} else if (action.equalsIgnoreCase("clearerror")) {
|
2022-10-25 09:58:57 +02:00
|
|
|
if (args.argsLength() < 3)
|
|
|
|
throw new CommandException(Messages.NPC_COMMAND_INVALID_ERROR_MESSAGE,
|
|
|
|
Util.listValuesPretty(CommandTraitError.values()));
|
|
|
|
|
2022-10-24 16:01:40 +02:00
|
|
|
CommandTraitError which = Util.matchEnum(CommandTraitError.values(), args.getString(2));
|
|
|
|
if (which == null)
|
|
|
|
throw new CommandException(Messages.NPC_COMMAND_INVALID_ERROR_MESSAGE,
|
|
|
|
Util.listValuesPretty(CommandTraitError.values()));
|
2023-03-25 14:47:42 +01:00
|
|
|
|
2023-10-01 11:27:38 +02:00
|
|
|
commands.clearHistory(which, args.argsLength() > 3 ? args.getString(3) : null);
|
2022-10-25 11:07:11 +02:00
|
|
|
Messaging.send(sender, Messages.NPC_COMMAND_ERRORS_CLEARED, Util.prettyEnum(which));
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("sequential")) {
|
2020-07-03 16:59:18 +02:00
|
|
|
commands.setExecutionMode(commands.getExecutionMode() == ExecutionMode.SEQUENTIAL ? ExecutionMode.LINEAR
|
|
|
|
: ExecutionMode.SEQUENTIAL);
|
2020-06-10 20:24:03 +02:00
|
|
|
Messaging.sendTr(sender,
|
2020-07-03 16:59:18 +02:00
|
|
|
commands.getExecutionMode() == ExecutionMode.SEQUENTIAL ? Messages.COMMANDS_SEQUENTIAL_SET
|
|
|
|
: Messages.COMMANDS_SEQUENTIAL_UNSET);
|
2022-11-28 16:10:50 +01:00
|
|
|
} else if (action.equalsIgnoreCase("persistsequence")) {
|
|
|
|
if (args.argsLength() == 2) {
|
|
|
|
commands.setPersistSequence(!commands.persistSequence());
|
|
|
|
} else {
|
|
|
|
commands.setPersistSequence(Boolean.parseBoolean(args.getString(3)));
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, commands.persistSequence() ? Messages.COMMANDS_PERSIST_SEQUENCE_SET
|
|
|
|
: Messages.COMMANDS_PERSIST_SEQUENCE_UNSET);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("remove")) {
|
2019-09-23 14:29:31 +02:00
|
|
|
if (args.argsLength() == 2)
|
|
|
|
throw new CommandUsageException();
|
2022-02-19 06:35:16 +01:00
|
|
|
int id = args.getInteger(2, -1);
|
2019-09-23 14:29:31 +02:00
|
|
|
if (!commands.hasCommandId(id))
|
|
|
|
throw new CommandException(Messages.COMMAND_UNKNOWN_COMMAND_ID, id);
|
|
|
|
commands.removeCommandById(id);
|
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_REMOVED, id);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("permissions") || action.equalsIgnoreCase("perms")) {
|
2022-09-14 20:35:42 +02:00
|
|
|
if (!sender.hasPermission("citizens.admin"))
|
|
|
|
throw new NoPermissionsException();
|
2020-04-30 15:32:38 +02:00
|
|
|
List<String> temporaryPermissions = Arrays.asList(args.getSlice(2));
|
|
|
|
commands.setTemporaryPermissions(temporaryPermissions);
|
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_TEMPORARY_PERMISSIONS_SET,
|
|
|
|
Joiner.on(' ').join(temporaryPermissions));
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("cost")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2023-06-25 07:41:19 +02:00
|
|
|
throw new CommandException(Messages.COMMAND_MISSING_COST);
|
|
|
|
if (args.argsLength() == 4) {
|
|
|
|
commands.setCost(args.getDouble(2), args.getInteger(3));
|
2023-06-25 15:58:09 +02:00
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_COST_SET,
|
|
|
|
args.getDouble(2) == -1 ? "-1 (default)" : args.getDouble(2), args.getInteger(3));
|
|
|
|
} else {
|
2023-06-25 07:41:19 +02:00
|
|
|
commands.setCost(args.getDouble(2));
|
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_COST_SET, args.getDouble(2));
|
|
|
|
}
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("expcost")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2023-06-25 07:41:19 +02:00
|
|
|
throw new CommandException(Messages.COMMAND_MISSING_COST);
|
|
|
|
if (args.argsLength() == 4) {
|
|
|
|
commands.setExperienceCost(args.getInteger(2), args.getInteger(3));
|
2023-06-25 15:58:09 +02:00
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_INDIVIDUAL_EXPERIENCE_COST_SET,
|
|
|
|
args.getInteger(2) == -1 ? "-1 (default)" : args.getInteger(2), args.getInteger(3));
|
|
|
|
} else {
|
2023-06-25 07:41:19 +02:00
|
|
|
commands.setExperienceCost(args.getInteger(2));
|
|
|
|
Messaging.sendTr(sender, Messages.COMMAND_EXPERIENCE_COST_SET, args.getInteger(2));
|
|
|
|
}
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("hideerrors")) {
|
2021-11-19 16:32:28 +01:00
|
|
|
commands.setHideErrorMessages(!commands.isHideErrorMessages());
|
|
|
|
Messaging.sendTr(sender, commands.isHideErrorMessages() ? Messages.COMMAND_HIDE_ERROR_MESSAGES_SET
|
|
|
|
: Messages.COMMAND_HIDE_ERROR_MESSAGES_UNSET);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("random")) {
|
2020-07-03 16:59:18 +02:00
|
|
|
commands.setExecutionMode(
|
|
|
|
commands.getExecutionMode() == ExecutionMode.RANDOM ? ExecutionMode.LINEAR : ExecutionMode.RANDOM);
|
|
|
|
Messaging.sendTr(sender, commands.getExecutionMode() == ExecutionMode.RANDOM ? Messages.COMMANDS_RANDOM_SET
|
|
|
|
: Messages.COMMANDS_RANDOM_UNSET);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("itemcost")) {
|
2021-02-01 15:35:28 +01:00
|
|
|
if (!(sender instanceof Player))
|
2022-07-17 16:29:11 +02:00
|
|
|
throw new CommandException(CommandMessages.MUST_BE_INGAME);
|
2023-06-25 07:41:19 +02:00
|
|
|
if (args.argsLength() == 2) {
|
2023-11-05 13:58:37 +01:00
|
|
|
InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands)).present((Player) sender);
|
2023-06-25 15:58:09 +02:00
|
|
|
} else {
|
|
|
|
InventoryMenu.createSelfRegistered(new ItemRequirementGUI(commands, args.getInteger(2)))
|
2023-11-05 13:58:37 +01:00
|
|
|
.present((Player) sender);
|
2023-06-25 07:41:19 +02:00
|
|
|
}
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("errormsg")) {
|
2022-10-24 16:01:40 +02:00
|
|
|
CommandTraitError which = Util.matchEnum(CommandTraitError.values(), args.getString(2));
|
2022-08-21 10:15:40 +02:00
|
|
|
if (which == null)
|
|
|
|
throw new CommandException(Messages.NPC_COMMAND_INVALID_ERROR_MESSAGE,
|
2022-10-24 16:01:40 +02:00
|
|
|
Util.listValuesPretty(CommandTraitError.values()));
|
2022-08-21 10:15:40 +02:00
|
|
|
commands.setCustomErrorMessage(which, args.getString(3));
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2019-09-23 14:29:31 +02:00
|
|
|
throw new CommandUsageException();
|
|
|
|
}
|
|
|
|
|
2023-04-07 20:35:55 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "configgui",
|
|
|
|
desc = "Display NPC configuration GUI",
|
|
|
|
modifiers = { "configgui" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.configgui")
|
|
|
|
public void configgui(CommandContext args, Player sender, NPC npc) {
|
|
|
|
InventoryMenu.createSelfRegistered(new NPCConfigurator(npc)).present(sender);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-06 20:11:07 +02:00
|
|
|
usage = "controllable|control (-m(ount),-y,-n,-o(wner required))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Toggles whether the NPC can be ridden and controlled",
|
|
|
|
modifiers = { "controllable", "control" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "myno")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void controllable(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (npc.isSpawned()
|
|
|
|
&& !sender.hasPermission(
|
|
|
|
"citizens.npc.controllable." + npc.getEntity().getType().name().toLowerCase().replace("_", ""))
|
2017-12-30 08:36:36 +01:00
|
|
|
|| !sender.hasPermission("citizens.npc.controllable"))
|
|
|
|
throw new NoPermissionsException();
|
|
|
|
if (!npc.hasTrait(Controllable.class)) {
|
|
|
|
npc.addTrait(new Controllable(false));
|
|
|
|
}
|
2020-09-14 11:57:58 +02:00
|
|
|
Controllable trait = npc.getOrAddTrait(Controllable.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
boolean enabled = trait.toggle();
|
|
|
|
if (args.hasFlag('y')) {
|
|
|
|
enabled = trait.setEnabled(true);
|
|
|
|
} else if (args.hasFlag('n')) {
|
|
|
|
enabled = trait.setEnabled(false);
|
|
|
|
}
|
|
|
|
trait.setOwnerRequired(args.hasFlag('o'));
|
|
|
|
String key = enabled ? Messages.CONTROLLABLE_SET : Messages.CONTROLLABLE_REMOVED;
|
|
|
|
Messaging.sendTr(sender, key, npc.getName());
|
|
|
|
if (enabled && args.hasFlag('m') && sender instanceof Player) {
|
|
|
|
trait.mount((Player) sender);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "copy (--name newname)",
|
|
|
|
desc = "Copies an NPC",
|
|
|
|
modifiers = { "copy" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.copy")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void copy(CommandContext args, CommandSender sender, NPC npc, @Flag("name") String name)
|
|
|
|
throws CommandException {
|
|
|
|
if (name == null) {
|
2022-12-24 06:36:24 +01:00
|
|
|
name = npc.getRawName();
|
2022-09-06 20:11:07 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
NPC copy = npc.clone();
|
2022-12-24 06:36:24 +01:00
|
|
|
if (!copy.getRawName().equals(name)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
copy.setName(name);
|
|
|
|
}
|
2022-10-02 17:10:23 +02:00
|
|
|
if (copy.getOrAddTrait(Spawned.class).shouldSpawn() && args.getSenderLocation() != null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Location location = args.getSenderLocation();
|
|
|
|
location.getChunk().load();
|
|
|
|
copy.teleport(location, TeleportCause.COMMAND);
|
2020-09-14 11:57:58 +02:00
|
|
|
copy.getOrAddTrait(CurrentLocation.class).setLocation(location);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2019-04-23 16:39:51 +02:00
|
|
|
CommandSenderCreateNPCEvent event = sender instanceof Player
|
|
|
|
? new PlayerCloneNPCEvent((Player) sender, npc, copy)
|
|
|
|
: new CommandSenderCloneNPCEvent(sender, npc, copy);
|
2017-12-30 08:36:36 +01:00
|
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
event.getNPC().destroy();
|
|
|
|
String reason = "Couldn't create NPC.";
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!event.getCancelReason().isEmpty()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
reason += " Reason: " + event.getCancelReason();
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(reason);
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_COPIED, npc.getName());
|
|
|
|
selector.select(sender, copy);
|
2022-02-19 07:36:45 +01:00
|
|
|
history.add(sender, new CreateNPCHistoryItem(copy));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-08-06 12:57:42 +02:00
|
|
|
usage = "create [name] ((-b(aby),u(nspawned),s(ilent),t(emporary),c(enter),p(acket)) --at [x,y,z,world] --type [type] --item (item) --trait ['trait1, trait2...'] --model [model name] --nameplate [true|false|hover] --temporaryticks [ticks] --registry [registry name]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Create a new NPC",
|
2023-01-26 18:54:13 +01:00
|
|
|
flags = "bustpc",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "create" },
|
|
|
|
min = 2,
|
|
|
|
permission = "citizens.npc.create")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
2022-09-06 20:11:07 +02:00
|
|
|
public void create(CommandContext args, CommandSender sender, NPC npc, @Flag("at") Location at,
|
|
|
|
@Flag(value = "type", defValue = "PLAYER") EntityType type, @Flag("trait") String traits,
|
2022-12-29 16:26:02 +01:00
|
|
|
@Flag(value = "nameplate", completions = { "true", "false", "hover" }) String nameplate,
|
2023-03-12 15:29:41 +01:00
|
|
|
@Flag("temporaryticks") Integer temporaryTicks, @Flag("item") String item,
|
2022-12-29 16:26:02 +01:00
|
|
|
@Flag("template") String templateName, @Flag("registry") String registryName) throws CommandException {
|
2022-12-18 06:50:19 +01:00
|
|
|
String name = args.getJoinedStrings(1).trim();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasValueFlag("type")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (type == null)
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messaging.tr(Messages.NPC_CREATE_INVALID_MOBTYPE, args.getFlag("type")));
|
2023-11-05 13:58:37 +01:00
|
|
|
else if (!EntityControllers.controllerExistsForType(type))
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messaging.tr(Messages.NPC_CREATE_MISSING_MOBTYPE, args.getFlag("type")));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-05-15 06:26:21 +02:00
|
|
|
int nameLength = SpigotUtil.getMaxNameLength(type);
|
2022-12-25 17:20:21 +01:00
|
|
|
if (Placeholders.replace(Messaging.parseComponents(name), sender, npc).length() > nameLength) {
|
2020-02-21 16:52:53 +01:00
|
|
|
Messaging.sendErrorTr(sender, Messages.NPC_NAME_TOO_LONG, nameLength);
|
2017-12-30 08:36:36 +01:00
|
|
|
name = name.substring(0, nameLength);
|
|
|
|
}
|
|
|
|
if (name.length() == 0)
|
|
|
|
throw new CommandException();
|
|
|
|
|
|
|
|
if (!sender.hasPermission("citizens.npc.create.*") && !sender.hasPermission("citizens.npc.createall")
|
|
|
|
&& !sender.hasPermission("citizens.npc.create." + type.name().toLowerCase().replace("_", "")))
|
|
|
|
throw new NoPermissionsException();
|
2023-06-12 15:20:51 +02:00
|
|
|
|
2023-06-11 11:06:22 +02:00
|
|
|
if ((at != null || registryName != null || traits != null || templateName != null)
|
|
|
|
&& !sender.hasPermission("citizens.npc.admin"))
|
|
|
|
throw new NoPermissionsException();
|
2022-04-23 07:42:48 +02:00
|
|
|
|
2021-02-22 12:26:12 +01:00
|
|
|
NPCRegistry registry = CitizensAPI.getNPCRegistry();
|
2022-09-06 20:11:07 +02:00
|
|
|
if (registryName != null) {
|
|
|
|
registry = CitizensAPI.getNamedNPCRegistry(registryName);
|
2021-02-22 12:26:12 +01:00
|
|
|
if (registry == null) {
|
2023-04-23 10:38:12 +02:00
|
|
|
registry = CitizensAPI.createNamedNPCRegistry(registryName, new MemoryNPCDataStore());
|
|
|
|
Messaging.send(sender, "An in-memory registry has been created named [[" + registryName + "]].");
|
2021-02-22 12:26:12 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-29 16:26:02 +01:00
|
|
|
if (args.hasFlag('t') || temporaryTicks != null) {
|
2021-02-27 07:41:05 +01:00
|
|
|
registry = temporaryRegistry;
|
|
|
|
}
|
2022-12-03 13:50:06 +01:00
|
|
|
if (item != null) {
|
2023-07-03 18:43:58 +02:00
|
|
|
ItemStack stack = Util.parseItemStack(null, item);
|
2022-12-03 13:50:06 +01:00
|
|
|
npc = registry.createNPCUsingItem(type, name, stack);
|
|
|
|
} else {
|
|
|
|
npc = registry.createNPC(type, name);
|
|
|
|
}
|
2022-04-23 07:42:48 +02:00
|
|
|
String msg = "Created [[" + npc.getName() + "]] (ID [[" + npc.getId() + "]])";
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
if (args.hasFlag('b')) {
|
2022-06-08 06:48:58 +02:00
|
|
|
msg += " as a baby";
|
2023-03-13 14:46:52 +01:00
|
|
|
npc.getOrAddTrait(Age.class).setAge(-24000);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-07-17 19:00:23 +02:00
|
|
|
if (args.hasFlag('s')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().set(NPC.Metadata.SILENT, true);
|
2020-07-17 19:00:23 +02:00
|
|
|
}
|
2022-12-29 16:26:02 +01:00
|
|
|
if (nameplate != null) {
|
|
|
|
npc.data().set(NPC.Metadata.NAMEPLATE_VISIBLE,
|
|
|
|
nameplate.equalsIgnoreCase("hover") ? nameplate.toLowerCase() : Boolean.parseBoolean(nameplate));
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!Setting.SERVER_OWNS_NPCS.asBoolean()) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(Owner.class).setOwner(sender);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-12-29 16:26:02 +01:00
|
|
|
if (temporaryTicks != null) {
|
2023-11-05 13:58:37 +01:00
|
|
|
NPC temp = npc;
|
2022-12-29 16:26:02 +01:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
if (temporaryRegistry.getByUniqueId(temp.getUniqueId()) == temp) {
|
|
|
|
temp.destroy();
|
|
|
|
}
|
|
|
|
}, temporaryTicks);
|
|
|
|
}
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(MobType.class).setType(type);
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2023-01-26 18:54:13 +01:00
|
|
|
if (args.hasFlag('p')) {
|
|
|
|
npc.addTrait(PacketNPC.class);
|
|
|
|
}
|
2023-08-06 12:57:42 +02:00
|
|
|
Location spawnLoc = args.getSenderLocation();
|
2022-09-06 20:11:07 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
CommandSenderCreateNPCEvent event = sender instanceof Player ? new PlayerCreateNPCEvent((Player) sender, npc)
|
|
|
|
: new CommandSenderCreateNPCEvent(sender, npc);
|
|
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
npc.destroy();
|
|
|
|
String reason = "Couldn't create NPC.";
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!event.getCancelReason().isEmpty()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
reason += " Reason: " + event.getCancelReason();
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(reason);
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (at != null) {
|
|
|
|
spawnLoc = at;
|
2019-12-03 12:01:29 +01:00
|
|
|
spawnLoc.getChunk().load();
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (spawnLoc == null) {
|
|
|
|
npc.destroy();
|
|
|
|
throw new CommandException(Messages.INVALID_SPAWN_LOCATION);
|
|
|
|
}
|
2022-12-24 14:43:08 +01:00
|
|
|
if (args.hasFlag('c')) {
|
|
|
|
spawnLoc = Util.getCenterLocation(spawnLoc.getBlock());
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!args.hasFlag('u')) {
|
2018-08-08 10:08:38 +02:00
|
|
|
npc.spawn(spawnLoc, SpawnReason.CREATE);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (traits != null) {
|
|
|
|
Iterable<String> parts = Splitter.on(',').trimResults().split(traits);
|
2017-12-30 08:36:36 +01:00
|
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
for (String tr : parts) {
|
|
|
|
Trait trait = CitizensAPI.getTraitFactory().getTrait(tr);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (trait == null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
npc.addTrait(trait);
|
|
|
|
builder.append(StringHelper.wrap(tr) + ", ");
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (builder.length() > 0) {
|
2017-12-30 08:36:36 +01:00
|
|
|
builder.delete(builder.length() - 2, builder.length());
|
2022-09-06 20:11:07 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
msg += " with traits " + builder.toString();
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (templateName != null) {
|
|
|
|
Iterable<String> parts = Splitter.on(',').trimResults().split(templateName);
|
2017-12-30 08:36:36 +01:00
|
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
for (String part : parts) {
|
|
|
|
Template template = Template.byName(part);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (template == null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
template.apply(npc);
|
|
|
|
builder.append(StringHelper.wrap(part) + ", ");
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (builder.length() > 0) {
|
2017-12-30 08:36:36 +01:00
|
|
|
builder.delete(builder.length() - 2, builder.length());
|
2022-09-06 20:11:07 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
msg += " with templates " + builder.toString();
|
|
|
|
}
|
|
|
|
selector.select(sender, npc);
|
2022-02-19 07:36:45 +01:00
|
|
|
history.add(sender, new CreateNPCHistoryItem(npc));
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.send(sender, msg + '.');
|
|
|
|
}
|
|
|
|
|
2022-07-15 04:21:44 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-08-22 16:51:33 +02:00
|
|
|
usage = "debug -p(aths) -n(avigation)",
|
2022-07-15 04:21:44 +02:00
|
|
|
desc = "Display debugging information",
|
|
|
|
modifiers = { "debug" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2022-08-22 16:51:33 +02:00
|
|
|
flags = "pn",
|
2022-07-15 04:21:44 +02:00
|
|
|
permission = "citizens.npc.debug")
|
|
|
|
@Requirements(ownership = true, selected = true)
|
|
|
|
public void debug(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
if (args.hasFlag('p')) {
|
|
|
|
npc.getNavigator().getDefaultParameters().debug(!npc.getNavigator().getDefaultParameters().debug());
|
|
|
|
Messaging.send(sender, "Path debugging set to " + npc.getNavigator().getDefaultParameters().debug());
|
|
|
|
} else if (args.hasFlag('n')) {
|
2022-07-25 09:40:39 +02:00
|
|
|
String output = "Use new finder [[" + npc.getNavigator().getDefaultParameters().useNewPathfinder();
|
|
|
|
output += "]] distance margin [[" + npc.getNavigator().getDefaultParameters().distanceMargin()
|
|
|
|
+ "]] (path margin [[" + npc.getNavigator().getDefaultParameters().pathDistanceMargin() + "]])<br>";
|
2022-07-15 04:21:44 +02:00
|
|
|
output += "Teleport if below " + npc.getNavigator().getDefaultParameters().destinationTeleportMargin()
|
|
|
|
+ " blocks<br>";
|
2022-07-25 09:40:39 +02:00
|
|
|
output += "Range [[" + npc.getNavigator().getDefaultParameters().range() + "]] speed [["
|
|
|
|
+ npc.getNavigator().getDefaultParameters().speed() + "]]<br>";
|
|
|
|
output += "Stuck action [[" + npc.getNavigator().getDefaultParameters().stuckAction() + "]]<br>";
|
2022-07-15 04:21:44 +02:00
|
|
|
Messaging.send(sender, output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-29 17:26:02 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "deselect",
|
|
|
|
desc = "Deselect currently selected NPC",
|
|
|
|
modifiers = { "deselect", "desel" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.deselect")
|
|
|
|
@Requirements
|
2023-11-05 13:58:37 +01:00
|
|
|
public void deselect(CommandContext args, CommandSender sender, NPC npc) {
|
2023-07-29 17:26:02 +02:00
|
|
|
selector.deselect(sender);
|
|
|
|
Messaging.sendTr(sender, Messages.DESELECTED_NPC);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "despawn (id)",
|
|
|
|
desc = "Despawn a NPC",
|
|
|
|
modifiers = { "despawn" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.despawn")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
2023-11-05 13:58:37 +01:00
|
|
|
public void despawn(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2023-03-14 13:55:33 +01:00
|
|
|
NPCCommandSelector.Callback callback = npc1 -> {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (npc1 == null)
|
2023-03-14 13:55:33 +01:00
|
|
|
throw new CommandException(Messages.NO_NPC_WITH_ID_FOUND, args.getString(1));
|
|
|
|
npc1.getOrAddTrait(Spawned.class).setSpawned(false);
|
|
|
|
npc1.despawn(DespawnReason.REMOVAL);
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_DESPAWNED, npc1.getName());
|
2017-12-30 08:36:36 +01:00
|
|
|
};
|
|
|
|
if (npc == null || args.argsLength() == 2) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() < 2)
|
2022-07-17 16:29:11 +02:00
|
|
|
throw new CommandException(CommandMessages.MUST_HAVE_SELECTED);
|
2019-03-01 13:50:44 +01:00
|
|
|
NPCCommandSelector.startWithCallback(callback, CitizensAPI.getNPCRegistry(), sender, args,
|
|
|
|
args.getString(1));
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
|
|
|
callback.run(npc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-07 11:45:10 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "drops",
|
|
|
|
desc = "Edit an NPC's drops",
|
|
|
|
modifiers = { "drops" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.drops")
|
|
|
|
@Requirements(ownership = true, selected = true)
|
|
|
|
public void drops(CommandContext args, Player sender, NPC npc) throws CommandException {
|
|
|
|
DropsTrait trait = npc.getOrAddTrait(DropsTrait.class);
|
|
|
|
trait.displayEditor(sender);
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:29:15 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2021-11-20 16:46:09 +01:00
|
|
|
usage = "endercrystal -b(ottom)",
|
2021-02-18 16:29:15 +01:00
|
|
|
desc = "Edit endercrystal modifiers",
|
|
|
|
modifiers = { "endercrystal" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2021-11-20 16:46:09 +01:00
|
|
|
flags = "b",
|
2021-02-18 16:29:15 +01:00
|
|
|
permission = "citizens.npc.endercrystal")
|
|
|
|
@Requirements(ownership = true, selected = true, types = EntityType.ENDER_CRYSTAL)
|
|
|
|
public void endercrystal(CommandContext args, Player sender, NPC npc) throws CommandException {
|
|
|
|
if (args.hasFlag('b')) {
|
|
|
|
EnderCrystalTrait trait = npc.getOrAddTrait(EnderCrystalTrait.class);
|
|
|
|
boolean showing = !trait.isShowBase();
|
|
|
|
trait.setShowBase(showing);
|
|
|
|
Messaging.sendTr(sender,
|
|
|
|
showing ? Messages.ENDERCRYSTAL_SHOWING_BOTTOM : Messages.ENDERCRYSTAL_NOT_SHOWING_BOTTOM,
|
|
|
|
npc.getName());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw new CommandException();
|
|
|
|
}
|
|
|
|
|
2020-06-27 09:41:47 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-06 20:11:07 +02:00
|
|
|
usage = "enderman -a(ngry)",
|
2020-06-27 09:41:47 +02:00
|
|
|
desc = "Set enderman modifiers",
|
|
|
|
flags = "a",
|
|
|
|
modifiers = { "enderman" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.enderman")
|
|
|
|
public void enderman(CommandContext args, Player sender, NPC npc) throws CommandException {
|
|
|
|
if (args.hasFlag('a')) {
|
2020-09-14 11:57:58 +02:00
|
|
|
boolean angry = npc.getOrAddTrait(EndermanTrait.class).toggleAngry();
|
2020-06-27 09:41:47 +02:00
|
|
|
Messaging.sendTr(sender, angry ? Messages.ENDERMAN_ANGRY_SET : Messages.ENDERMAN_ANGRY_UNSET,
|
|
|
|
npc.getName());
|
|
|
|
}
|
|
|
|
throw new CommandUsageException();
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "flyable (true|false)",
|
|
|
|
desc = "Toggles or sets an NPC's flyable status",
|
|
|
|
modifiers = { "flyable" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.flyable")
|
|
|
|
@Requirements(
|
|
|
|
selected = true,
|
|
|
|
ownership = true,
|
|
|
|
excludedTypes = { EntityType.BAT, EntityType.BLAZE, EntityType.ENDER_DRAGON, EntityType.GHAST,
|
|
|
|
EntityType.WITHER })
|
2022-09-07 21:01:39 +02:00
|
|
|
public void flyable(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Boolean explicit)
|
|
|
|
throws CommandException {
|
|
|
|
boolean flyable = explicit != null ? explicit : !npc.isFlyable();
|
2017-12-30 08:36:36 +01:00
|
|
|
npc.setFlyable(flyable);
|
2022-09-07 21:01:39 +02:00
|
|
|
flyable = npc.isFlyable(); // may not have applied, eg bats are always flyable
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, flyable ? Messages.FLYABLE_SET : Messages.FLYABLE_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-10-28 20:09:08 +02:00
|
|
|
usage = "follow (player name|NPC id) (-p[rotect]) (--margin [margin]) (--enable [boolean])",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Toggles NPC following you",
|
|
|
|
flags = "p",
|
|
|
|
modifiers = { "follow" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.follow")
|
2023-10-28 20:09:08 +02:00
|
|
|
public void follow(CommandContext args, CommandSender sender, NPC npc, @Flag("margin") Double margin,
|
|
|
|
@Flag("enable") Boolean explicit) throws CommandException {
|
2018-10-06 11:11:57 +02:00
|
|
|
boolean protect = args.hasFlag('p');
|
2023-05-05 18:45:57 +02:00
|
|
|
FollowTrait trait = npc.getOrAddTrait(FollowTrait.class);
|
2023-10-01 11:27:38 +02:00
|
|
|
if (margin != null) {
|
|
|
|
trait.setFollowingMargin(margin);
|
|
|
|
Messaging.sendTr(sender, Messages.FOLLOW_MARGIN_SET, npc.getName(), margin);
|
|
|
|
return;
|
|
|
|
}
|
2023-05-05 18:45:57 +02:00
|
|
|
trait.setProtect(protect);
|
2018-10-06 11:11:57 +02:00
|
|
|
String name = sender.getName();
|
|
|
|
if (args.argsLength() > 1) {
|
|
|
|
name = args.getString(1);
|
|
|
|
}
|
2018-10-06 12:31:16 +02:00
|
|
|
OfflinePlayer player = Bukkit.getOfflinePlayer(name);
|
2022-02-11 11:46:11 +01:00
|
|
|
if (!player.hasPlayedBefore() && !player.isOnline()) {
|
2023-03-14 13:55:33 +01:00
|
|
|
NPCCommandSelector.Callback callback = followingNPC -> {
|
|
|
|
if (followingNPC == null)
|
|
|
|
throw new CommandException(CommandMessages.MUST_HAVE_SELECTED);
|
|
|
|
if (!(sender instanceof ConsoleCommandSender)
|
|
|
|
&& !followingNPC.getOrAddTrait(Owner.class).isOwnedBy(sender))
|
|
|
|
throw new CommandException(CommandMessages.MUST_BE_OWNER);
|
2023-05-05 18:45:57 +02:00
|
|
|
boolean following = !trait.isEnabled();
|
|
|
|
trait.follow(following ? followingNPC.getEntity() : null);
|
2023-03-18 16:28:33 +01:00
|
|
|
Messaging.sendTr(sender, following ? Messages.FOLLOW_SET : Messages.FOLLOW_UNSET, npc.getName(),
|
|
|
|
followingNPC.getName());
|
2021-02-07 11:45:10 +01:00
|
|
|
};
|
|
|
|
NPCCommandSelector.startWithCallback(callback, CitizensAPI.getNPCRegistry(), sender, args,
|
|
|
|
args.getString(1));
|
|
|
|
return;
|
2018-10-06 12:31:16 +02:00
|
|
|
}
|
2023-10-28 20:09:08 +02:00
|
|
|
boolean following = explicit == null ? !trait.isEnabled() : explicit;
|
2023-05-05 18:45:57 +02:00
|
|
|
trait.follow(following ? player.getPlayer() : null);
|
2018-10-06 12:31:16 +02:00
|
|
|
Messaging.sendTr(sender, following ? Messages.FOLLOW_SET : Messages.FOLLOW_UNSET, npc.getName(),
|
|
|
|
player.getName());
|
2018-10-06 11:11:57 +02:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "gamemode [gamemode]",
|
|
|
|
desc = "Changes the gamemode",
|
|
|
|
modifiers = { "gamemode" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.gamemode")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.PLAYER })
|
2022-09-07 21:01:39 +02:00
|
|
|
public void gamemode(CommandContext args, CommandSender sender, NPC npc, @Arg(1) GameMode mode) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Player player = (Player) npc.getEntity();
|
|
|
|
if (args.argsLength() == 1) {
|
|
|
|
Messaging.sendTr(sender, Messages.GAMEMODE_DESCRIBE, npc.getName(),
|
|
|
|
player.getGameMode().name().toLowerCase());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (mode == null) {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.GAMEMODE_INVALID, args.getString(1));
|
|
|
|
return;
|
|
|
|
}
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(GameModeTrait.class).setGameMode(mode);
|
2022-09-07 21:01:39 +02:00
|
|
|
Messaging.sendTr(sender, Messages.GAMEMODE_SET, Util.prettyEnum(mode));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "glowing --color [minecraft chat color]",
|
|
|
|
desc = "Toggles an NPC's glowing status",
|
|
|
|
modifiers = { "glowing" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.glowing")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2022-09-06 20:11:07 +02:00
|
|
|
public void glowing(CommandContext args, CommandSender sender, NPC npc, @Flag("color") ChatColor color)
|
|
|
|
throws CommandException {
|
|
|
|
if (color != null) {
|
|
|
|
npc.getOrAddTrait(ScoreboardTrait.class).setColor(color);
|
2022-02-19 12:00:09 +01:00
|
|
|
if (!npc.data().has(NPC.Metadata.GLOWING)) {
|
|
|
|
npc.data().setPersistent(NPC.Metadata.GLOWING, true);
|
2020-04-22 12:00:15 +02:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
Messaging.sendTr(sender, Messages.GLOWING_COLOR_SET, npc.getName(), color + Util.prettyEnum(color));
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-02-19 12:00:09 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.GLOWING, !npc.data().get(NPC.Metadata.GLOWING, false));
|
|
|
|
boolean glowing = npc.data().get(NPC.Metadata.GLOWING);
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, glowing ? Messages.GLOWING_SET : Messages.GLOWING_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "gravity",
|
|
|
|
desc = "Toggles gravity",
|
|
|
|
modifiers = { "gravity" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.gravity")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void gravity(CommandContext args, CommandSender sender, NPC npc) {
|
2022-05-26 09:58:54 +02:00
|
|
|
boolean nogravity = npc.getOrAddTrait(Gravity.class).toggle();
|
|
|
|
String key = !nogravity ? Messages.GRAVITY_ENABLED : Messages.GRAVITY_DISABLED;
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, key, npc.getName());
|
|
|
|
}
|
|
|
|
|
2023-01-03 13:55:27 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "hitbox --scale [scale] --width/height [value]",
|
|
|
|
desc = "Sets the NPC hitbox",
|
|
|
|
modifiers = { "hitbox" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.hitbox")
|
|
|
|
public void hitbox(CommandContext args, CommandSender sender, NPC npc, @Flag("scale") Float scale,
|
|
|
|
@Flag("width") Float width, @Flag("height") Float height) {
|
|
|
|
if (scale != null) {
|
|
|
|
npc.getOrAddTrait(BoundingBoxTrait.class).setScale(scale);
|
|
|
|
}
|
|
|
|
if (width != null) {
|
|
|
|
npc.getOrAddTrait(BoundingBoxTrait.class).setWidth(width);
|
|
|
|
}
|
|
|
|
if (height != null) {
|
|
|
|
npc.getOrAddTrait(BoundingBoxTrait.class).setHeight(height);
|
|
|
|
}
|
|
|
|
EntityDim dim = npc.getOrAddTrait(BoundingBoxTrait.class).getAdjustedBoundingBox();
|
|
|
|
Messaging.sendTr(sender, Messages.BOUNDING_BOX_SET, "width " + dim.width + " height " + dim.height);
|
|
|
|
}
|
|
|
|
|
2020-06-30 12:17:14 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-11-05 13:58:37 +01:00
|
|
|
usage = "hologram add [text] | set [line #] [text] | remove [line #] | clear | lineheight [height] | viewrange [range] | margintop [line #] [margin] | marginbottom [line #] [margin]",
|
2020-07-03 09:14:55 +02:00
|
|
|
desc = "Controls NPC hologram text",
|
2020-06-30 12:17:14 +02:00
|
|
|
modifiers = { "hologram" },
|
|
|
|
min = 1,
|
|
|
|
max = -1,
|
|
|
|
permission = "citizens.npc.hologram")
|
2023-11-05 13:58:37 +01:00
|
|
|
public void hologram(CommandContext args, CommandSender sender, NPC npc,
|
|
|
|
@Arg(
|
|
|
|
value = 1,
|
|
|
|
completions = { "add", "set", "remove", "clear", "lineheight", "viewrange", "margintop",
|
|
|
|
"marginbottom" }) String action,
|
2023-10-30 15:49:02 +01:00
|
|
|
@Arg(value = 2, completionsProvider = HologramTrait.TabCompletions.class) String secondCompletion)
|
2022-09-07 21:01:39 +02:00
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
|
2020-06-30 12:17:14 +02:00
|
|
|
if (args.argsLength() == 1) {
|
2020-07-03 09:14:55 +02:00
|
|
|
String output = Messaging.tr(Messages.HOLOGRAM_DESCRIBE_HEADER, npc.getName());
|
|
|
|
List<String> lines = trait.getLines();
|
|
|
|
for (int i = 0; i < lines.size(); i++) {
|
|
|
|
String line = lines.get(i);
|
|
|
|
output += "<br> [[" + i + "]] - " + line;
|
|
|
|
}
|
|
|
|
Messaging.send(sender, output);
|
2020-07-27 11:42:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2022-09-07 21:01:39 +02:00
|
|
|
if (action.equalsIgnoreCase("set")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2020-07-21 05:15:05 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
int idx = Math.max(0, args.getInteger(2));
|
2023-11-05 13:58:37 +01:00
|
|
|
if (idx >= trait.getLines().size())
|
2020-07-03 09:14:55 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 3)
|
2020-07-21 05:15:05 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_TEXT_MISSING);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
trait.setLine(idx, args.getJoinedStrings(3));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_LINE_SET, idx, args.getJoinedStrings(3));
|
2023-11-05 13:58:37 +01:00
|
|
|
} else if (action.equalsIgnoreCase("viewrange")) {
|
|
|
|
if (args.argsLength() == 2)
|
|
|
|
throw new CommandUsageException();
|
|
|
|
|
|
|
|
trait.setViewRange(args.getInteger(2));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_VIEW_RANGE_SET, npc.getName(), args.getInteger(2));
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("add")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2020-07-21 05:15:05 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_TEXT_MISSING);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
trait.addLine(args.getJoinedStrings(2));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_LINE_ADD, args.getJoinedStrings(2));
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("remove")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2020-07-21 05:15:05 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
int idx = Math.max(0, args.getInteger(2));
|
2023-11-05 13:58:37 +01:00
|
|
|
if (idx >= trait.getLines().size())
|
2020-07-03 09:14:55 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2022-04-24 20:22:39 +02:00
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
trait.removeLine(idx);
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_LINE_REMOVED, idx);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("clear")) {
|
2020-07-06 19:07:01 +02:00
|
|
|
trait.clear();
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_CLEARED);
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (action.equalsIgnoreCase("lineheight")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
|
|
|
throw new CommandUsageException();
|
|
|
|
|
2020-07-03 09:14:55 +02:00
|
|
|
trait.setLineHeight(args.getDouble(2));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_LINE_HEIGHT_SET, args.getDouble(2));
|
2023-06-17 18:08:44 +02:00
|
|
|
} else if (action.equalsIgnoreCase("margintop")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
2023-06-17 18:08:44 +02:00
|
|
|
int idx = Math.max(0, args.getInteger(2));
|
2023-11-05 13:58:37 +01:00
|
|
|
if (idx >= trait.getLines().size())
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
|
|
|
if (args.argsLength() == 3)
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_MARGIN_MISSING);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
2023-06-17 18:08:44 +02:00
|
|
|
trait.setMargin(idx, "top", args.getDouble(3));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_MARGIN_SET, idx, "top", args.getDouble(3));
|
|
|
|
} else if (action.equalsIgnoreCase("marginbottom")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() == 2)
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
2023-06-17 18:08:44 +02:00
|
|
|
int idx = Math.max(0, args.getInteger(2));
|
2023-11-05 13:58:37 +01:00
|
|
|
if (idx >= trait.getLines().size())
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_INVALID_LINE);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
|
|
|
if (args.argsLength() == 3)
|
2023-06-17 18:08:44 +02:00
|
|
|
throw new CommandException(Messages.HOLOGRAM_MARGIN_MISSING);
|
2023-11-05 13:58:37 +01:00
|
|
|
|
2023-06-17 18:08:44 +02:00
|
|
|
trait.setMargin(idx, "bottom", args.getDouble(3));
|
|
|
|
Messaging.sendTr(sender, Messages.HOLOGRAM_MARGIN_SET, idx, "bottom", args.getDouble(3));
|
2020-06-30 12:17:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 17:40:01 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-02-05 17:43:42 +01:00
|
|
|
usage = "homeloc --location [loc] --delay [delay] --distance [distance] -h(ere) -p(athfind) -t(eleport)",
|
2023-02-05 17:40:01 +01:00
|
|
|
desc = "Controls home location",
|
|
|
|
modifiers = { "home" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "pth",
|
|
|
|
permission = "citizens.npc.home")
|
|
|
|
@Requirements(ownership = true, selected = true)
|
|
|
|
public void home(CommandContext args, CommandSender sender, NPC npc, @Flag("location") Location loc,
|
2023-03-12 15:29:41 +01:00
|
|
|
@Flag("delay") Duration delay, @Flag("distance") Double distance) throws CommandException {
|
2023-02-05 17:40:01 +01:00
|
|
|
HomeTrait trait = npc.getOrAddTrait(HomeTrait.class);
|
|
|
|
String output = "";
|
|
|
|
if (args.hasFlag('h')) {
|
|
|
|
if (!(sender instanceof Player))
|
|
|
|
throw new RequirementMissingException(Messaging.tr(CommandMessages.REQUIREMENTS_MUST_BE_LIVING_ENTITY));
|
|
|
|
trait.setHomeLocation(((Player) sender).getLocation());
|
|
|
|
output += Messaging.tr(Messages.HOME_TRAIT_LOCATION_SET, Util.prettyPrintLocation(trait.getHomeLocation()));
|
|
|
|
}
|
|
|
|
if (loc != null) {
|
|
|
|
trait.setHomeLocation(loc);
|
2023-02-05 17:43:42 +01:00
|
|
|
output += " "
|
|
|
|
+ Messaging.tr(Messages.HOME_TRAIT_LOCATION_SET, Util.prettyPrintLocation(trait.getHomeLocation()));
|
|
|
|
}
|
|
|
|
if (distance != null) {
|
|
|
|
trait.setDistanceBlocks(distance);
|
|
|
|
output += " " + Messaging.tr(Messages.HOME_TRAIT_DISTANCE_SET, trait.getDistanceBlocks());
|
2023-02-05 17:40:01 +01:00
|
|
|
}
|
|
|
|
if (args.hasFlag('p')) {
|
|
|
|
trait.setReturnStrategy(HomeTrait.ReturnStrategy.PATHFIND);
|
2023-02-05 17:43:42 +01:00
|
|
|
output += " " + Messaging.tr(Messages.HOME_TRAIT_PATHFIND_SET, npc.getName());
|
2023-02-05 17:40:01 +01:00
|
|
|
}
|
|
|
|
if (args.hasFlag('t')) {
|
|
|
|
trait.setReturnStrategy(HomeTrait.ReturnStrategy.TELEPORT);
|
2023-02-05 17:43:42 +01:00
|
|
|
output += " " + Messaging.tr(Messages.HOME_TRAIT_TELEPORT_SET, npc.getName());
|
2023-02-05 17:40:01 +01:00
|
|
|
}
|
|
|
|
if (delay != null) {
|
2023-03-12 15:29:41 +01:00
|
|
|
trait.setDelayTicks(Util.toTicks(delay));
|
2023-04-25 17:56:50 +02:00
|
|
|
output += " " + Messaging.tr(Messages.HOME_TRAIT_DELAY_SET, Util.toTicks(delay));
|
2023-02-05 17:40:01 +01:00
|
|
|
}
|
|
|
|
if (!output.isEmpty()) {
|
2023-02-05 17:43:42 +01:00
|
|
|
Messaging.send(sender, output.trim());
|
2023-02-05 17:40:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-01-01 18:33:19 +01:00
|
|
|
usage = "horse|donkey|mule (--color color) (--type type) (--style style) (-cb)",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets horse and horse-like entity modifiers",
|
|
|
|
help = "Use the -c flag to make the NPC have a chest, or the -b flag to stop them from having a chest.",
|
2022-01-01 18:33:19 +01:00
|
|
|
modifiers = { "horse", "donkey", "mule" },
|
2020-02-14 15:48:40 +01:00
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "cb",
|
|
|
|
permission = "citizens.npc.horse")
|
2019-05-24 12:32:51 +02:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2022-09-06 20:11:07 +02:00
|
|
|
public void horse(CommandContext args, CommandSender sender, NPC npc,
|
|
|
|
@Flag({ "color", "colour" }) Horse.Color color, @Flag("style") Horse.Style style) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
EntityType type = npc.getOrAddTrait(MobType.class).getType();
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!Util.isHorse(type))
|
2019-05-24 12:32:51 +02:00
|
|
|
throw new CommandException(CommandMessages.REQUIREMENTS_INVALID_MOB_TYPE, Util.prettyEnum(type));
|
2020-09-14 11:57:58 +02:00
|
|
|
HorseModifiers horse = npc.getOrAddTrait(HorseModifiers.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
String output = "";
|
2022-01-01 18:33:19 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('c')) {
|
|
|
|
horse.setCarryingChest(true);
|
|
|
|
output += Messaging.tr(Messages.HORSE_CHEST_SET) + " ";
|
|
|
|
} else if (args.hasFlag('b')) {
|
|
|
|
horse.setCarryingChest(false);
|
|
|
|
output += Messaging.tr(Messages.HORSE_CHEST_UNSET) + " ";
|
|
|
|
}
|
2019-05-24 12:32:51 +02:00
|
|
|
if (type == EntityType.HORSE && (args.hasValueFlag("color") || args.hasValueFlag("colour"))) {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (color == null) {
|
2020-09-14 11:57:58 +02:00
|
|
|
String valid = Util.listValuesPretty(Horse.Color.values());
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_HORSE_COLOR, valid);
|
|
|
|
}
|
|
|
|
horse.setColor(color);
|
|
|
|
output += Messaging.tr(Messages.HORSE_COLOR_SET, Util.prettyEnum(color));
|
|
|
|
}
|
2019-05-24 12:32:51 +02:00
|
|
|
if (type == EntityType.HORSE && args.hasValueFlag("style")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (style == null) {
|
2020-09-14 11:57:58 +02:00
|
|
|
String valid = Util.listValuesPretty(Horse.Style.values());
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_HORSE_STYLE, valid);
|
|
|
|
}
|
|
|
|
horse.setStyle(style);
|
|
|
|
output += Messaging.tr(Messages.HORSE_STYLE_SET, Util.prettyEnum(style));
|
|
|
|
}
|
|
|
|
if (output.isEmpty()) {
|
2019-05-24 12:32:51 +02:00
|
|
|
Messaging.sendTr(sender, Messages.HORSE_DESCRIBE, Util.prettyEnum(horse.getColor()), Util.prettyEnum(type),
|
|
|
|
Util.prettyEnum(horse.getStyle()));
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2022-11-23 12:03:06 +01:00
|
|
|
Messaging.send(sender, output);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-06 15:25:12 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "hurt [damage]",
|
|
|
|
desc = "Damages the NPC",
|
|
|
|
modifiers = { "hurt" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.hurt")
|
2022-11-12 14:51:15 +01:00
|
|
|
public void hurt(CommandContext args, CommandSender sender, NPC npc) {
|
|
|
|
if (!(npc.getEntity() instanceof Damageable)) {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.NPC_NOT_DAMAGEABLE,
|
|
|
|
Util.prettyEnum(npc.getOrAddTrait(MobType.class).getType()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (npc.isProtected()) {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.NPC_PROTECTED);
|
|
|
|
return;
|
|
|
|
}
|
2022-05-06 15:25:12 +02:00
|
|
|
((Damageable) npc.getEntity()).damage(args.getInteger(1));
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "id",
|
|
|
|
desc = "Sends the selected NPC's ID to the sender",
|
|
|
|
modifiers = { "id" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.id")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void id(CommandContext args, CommandSender sender, NPC npc) {
|
2022-12-03 11:21:46 +01:00
|
|
|
sender.sendMessage(Integer.toString(npc.getId()));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "inventory",
|
|
|
|
desc = "Show's an NPC's inventory",
|
|
|
|
modifiers = { "inventory" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.inventory")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void inventory(CommandContext args, CommandSender sender, NPC npc) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(Inventory.class).openInventory((Player) sender);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-12-03 13:50:06 +01:00
|
|
|
usage = "item (item) (metadata) (-h(and))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets the NPC's item",
|
|
|
|
modifiers = { "item", },
|
2022-12-03 11:21:46 +01:00
|
|
|
min = 1,
|
2020-02-14 15:48:40 +01:00
|
|
|
max = 3,
|
2022-12-03 11:21:46 +01:00
|
|
|
flags = "h",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.item")
|
2022-12-03 11:21:46 +01:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2022-12-03 13:50:06 +01:00
|
|
|
public void item(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Material mat, @Arg(2) String modify)
|
|
|
|
throws CommandException {
|
2022-12-03 11:21:46 +01:00
|
|
|
EntityType type = npc.getOrAddTrait(MobType.class).getType();
|
2023-07-03 18:43:58 +02:00
|
|
|
if (!type.name().contains("ITEM_FRAME") && !type.name().contains("ITEM_DISPLAY")
|
2023-10-28 20:09:08 +02:00
|
|
|
&& !type.name().contains("BLOCK_DISPLAY") && type != EntityType.DROPPED_ITEM
|
|
|
|
&& type != EntityType.FALLING_BLOCK)
|
2023-07-03 18:43:58 +02:00
|
|
|
throw new CommandException(CommandMessages.REQUIREMENTS_INVALID_MOB_TYPE, Util.prettyEnum(type));
|
2022-12-03 13:50:06 +01:00
|
|
|
ItemStack stack = args.hasFlag('h') ? ((Player) sender).getItemInHand() : new ItemStack(mat, 1);
|
|
|
|
if (modify != null) {
|
2023-07-03 18:43:58 +02:00
|
|
|
stack = Util.parseItemStack(stack, modify);
|
2022-12-03 13:50:06 +01:00
|
|
|
}
|
2022-12-03 11:21:46 +01:00
|
|
|
if (mat == null && !args.hasFlag('h'))
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.UNKNOWN_MATERIAL);
|
2023-07-03 18:43:58 +02:00
|
|
|
ItemStack fstack = stack.clone();
|
|
|
|
npc.setItemProvider(() -> fstack);
|
2023-10-28 20:09:08 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc.isSpawned()) {
|
2018-08-08 10:08:38 +02:00
|
|
|
npc.despawn(DespawnReason.PENDING_RESPAWN);
|
|
|
|
npc.spawn(npc.getStoredLocation(), SpawnReason.RESPAWN);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-12-03 11:21:46 +01:00
|
|
|
Messaging.sendTr(sender, Messages.ITEM_SET, Util.prettyEnum(stack.getType()));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-10-08 05:11:40 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "jump",
|
|
|
|
desc = "Makes the NPC jump",
|
|
|
|
modifiers = { "jump" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.jump")
|
|
|
|
public void jump(CommandContext args, CommandSender sender, NPC npc) {
|
|
|
|
NMS.setShouldJump(npc.getEntity());
|
|
|
|
}
|
|
|
|
|
2023-06-14 17:45:36 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "knockback (--explicit true|false)",
|
|
|
|
desc = "Toggle NPC knockback",
|
|
|
|
modifiers = { "knockback" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.knockback")
|
|
|
|
public void knockback(CommandContext args, CommandSender sender, NPC npc, @Flag("explicit") Boolean explicit) {
|
|
|
|
boolean kb = !npc.data().get(NPC.Metadata.KNOCKBACK, true);
|
|
|
|
if (explicit != null) {
|
|
|
|
kb = explicit;
|
|
|
|
}
|
|
|
|
npc.data().set(NPC.Metadata.KNOCKBACK, kb);
|
|
|
|
Messaging.sendTr(sender, kb ? Messages.KNOCKBACK_SET : Messages.KNOCKBACK_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "leashable",
|
|
|
|
desc = "Toggles leashability",
|
|
|
|
modifiers = { "leashable" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "t",
|
|
|
|
permission = "citizens.npc.leashable")
|
2023-03-25 16:22:46 +01:00
|
|
|
@Requirements(selected = true, ownership = true, excludedTypes = { EntityType.PLAYER })
|
2017-12-30 08:36:36 +01:00
|
|
|
public void leashable(CommandContext args, CommandSender sender, NPC npc) {
|
2023-01-01 08:26:35 +01:00
|
|
|
boolean vulnerable = !npc.data().get(NPC.Metadata.LEASH_PROTECTED, true);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('t')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().set(NPC.Metadata.LEASH_PROTECTED, vulnerable);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.LEASH_PROTECTED, vulnerable);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
String key = vulnerable ? Messages.LEASHABLE_STOPPED : Messages.LEASHABLE_SET;
|
|
|
|
Messaging.sendTr(sender, key, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "list (page) ((-a) --owner (owner) --type (type) --char (char) --registry (name))",
|
|
|
|
desc = "List NPCs",
|
|
|
|
flags = "a",
|
|
|
|
modifiers = { "list" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.list")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
2022-09-06 20:11:07 +02:00
|
|
|
public void list(CommandContext args, CommandSender sender, NPC npc, @Flag("owner") String owner,
|
2022-09-08 23:43:25 +02:00
|
|
|
@Flag("type") EntityType type, @Flag("page") Integer page, @Flag("registry") String registry)
|
|
|
|
throws CommandException {
|
|
|
|
NPCRegistry source = registry != null ? CitizensAPI.getNamedNPCRegistry(registry)
|
2019-01-18 17:18:43 +01:00
|
|
|
: CitizensAPI.getNPCRegistry();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (source == null)
|
|
|
|
throw new CommandException();
|
2023-11-05 13:58:37 +01:00
|
|
|
List<NPC> npcs = new ArrayList<>();
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
if (args.hasFlag('a')) {
|
|
|
|
for (NPC add : source.sorted()) {
|
|
|
|
npcs.add(add);
|
|
|
|
}
|
2022-09-08 23:43:25 +02:00
|
|
|
} else if (owner != null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
for (NPC add : source.sorted()) {
|
2022-09-08 23:43:25 +02:00
|
|
|
if (!npcs.contains(add) && add.getOrAddTrait(Owner.class).isOwnedBy(owner)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
npcs.add(add);
|
|
|
|
}
|
|
|
|
}
|
2022-09-08 23:43:25 +02:00
|
|
|
} else if (sender instanceof Player) {
|
|
|
|
for (NPC add : source.sorted()) {
|
|
|
|
if (!npcs.contains(add) && add.getOrAddTrait(Owner.class).isOwnedBy(sender)) {
|
|
|
|
npcs.add(add);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
2022-09-08 23:43:25 +02:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("type")) {
|
|
|
|
if (type == null)
|
|
|
|
throw new CommandException(Messages.COMMAND_INVALID_MOBTYPE, type);
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2022-09-08 23:43:25 +02:00
|
|
|
for (Iterator<NPC> iterator = npcs.iterator(); iterator.hasNext();) {
|
|
|
|
if (iterator.next().getOrAddTrait(MobType.class).getType() != type) {
|
|
|
|
iterator.remove();
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-09 19:17:26 +02:00
|
|
|
Paginator paginator = new Paginator().header("NPCs").console(sender instanceof ConsoleCommandSender)
|
|
|
|
.enablePageSwitcher('/' + args.getRawCommand() + " --page $page");
|
|
|
|
for (int i = 0; i < npcs.size(); i++) {
|
2023-07-09 14:40:48 +02:00
|
|
|
String id = npcs.get(i).getUniqueId().toString();
|
2023-07-19 17:53:43 +02:00
|
|
|
String line = StringHelper.wrap(npcs.get(i).getId()) + " " + npcs.get(i).getName()
|
|
|
|
+ " (<click:run_command:/npc tp --uuid " + id
|
2023-07-09 12:57:30 +02:00
|
|
|
+ "><hover:show_text:Teleport to this NPC>[[tp]]</hover></click>) (<click:run_command:/npc tph --uuid "
|
2022-10-05 16:27:09 +02:00
|
|
|
+ id
|
|
|
|
+ "><hover:show_text:Teleport NPC to me>[[summon]]</hover></click>) (<click:run_command:/npc remove "
|
|
|
|
+ id + "><hover:show_text:Remove this NPC><red>-</red></hover></click>)";
|
2017-12-30 08:36:36 +01:00
|
|
|
paginator.addLine(line);
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
int op = page == null ? args.getInteger(1, 1) : page;
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!paginator.sendPage(sender, op))
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.COMMAND_PAGE_MISSING, op);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-04-29 18:18:24 +02:00
|
|
|
usage = "lookclose --range [range] -r[ealistic looking] --randomlook [true|false] --perplayer [true|false] --randomswitchtargets [true|false] --randompitchrange [min,max] --randomyawrange [min,max] --disablewhennavigating [true|false] --targetnpcs [true|false]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Toggle whether a NPC will look when a player is near",
|
2022-11-28 16:10:50 +01:00
|
|
|
modifiers = { "lookclose", "look" },
|
2020-02-14 15:48:40 +01:00
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2022-04-16 16:49:20 +02:00
|
|
|
flags = "r",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.lookclose")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void lookClose(CommandContext args, CommandSender sender, NPC npc,
|
|
|
|
@Flag({ "randomlook", "rlook" }) Boolean randomlook, @Flag("range") Double range,
|
2023-03-12 15:29:41 +01:00
|
|
|
@Flag("randomlookdelay") Duration randomLookDelay, @Flag("randomyawrange") String randomYaw,
|
2022-11-13 09:02:17 +01:00
|
|
|
@Flag("randompitchrange") String randomPitch, @Flag("randomswitchtargets") Boolean randomSwitchTargets,
|
2023-05-01 18:50:50 +02:00
|
|
|
@Flag("headonly") Boolean headonly, @Flag("linkedbody") Boolean linkedbody,
|
|
|
|
@Flag("disablewhennavigating") Boolean disableWhenNavigating, @Flag("perplayer") Boolean perPlayer,
|
|
|
|
@Flag("targetnpcs") Boolean targetNPCs) throws CommandException {
|
2019-04-26 15:14:15 +02:00
|
|
|
boolean toggle = true;
|
2022-04-16 16:49:20 +02:00
|
|
|
LookClose trait = npc.getOrAddTrait(LookClose.class);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (randomlook != null) {
|
|
|
|
trait.setRandomLook(randomlook);
|
|
|
|
Messaging.sendTr(sender, randomlook ? Messages.LOOKCLOSE_RANDOM_SET : Messages.LOOKCLOSE_RANDOM_STOPPED,
|
2019-04-26 15:14:15 +02:00
|
|
|
npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-12-11 14:28:39 +01:00
|
|
|
if (perPlayer != null) {
|
|
|
|
trait.setPerPlayer(perPlayer);
|
|
|
|
Messaging.sendTr(sender, perPlayer ? Messages.LOOKCLOSE_PERPLAYER_SET : Messages.LOOKCLOSE_PERPLAYER_UNSET,
|
|
|
|
npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2023-01-01 17:24:11 +01:00
|
|
|
if (headonly != null) {
|
|
|
|
trait.setHeadOnly(headonly);
|
|
|
|
Messaging.sendTr(sender, headonly ? Messages.HEADONLY_SET : Messages.HEADONLY_UNSET, npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2023-05-01 18:50:50 +02:00
|
|
|
if (linkedbody != null) {
|
|
|
|
trait.setLinkedBody(linkedbody);
|
|
|
|
Messaging.sendTr(sender, linkedbody ? Messages.LINKEDBODY_SET : Messages.LINKEDBODY_UNSET, npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-11-13 17:14:28 +01:00
|
|
|
if (randomSwitchTargets != null) {
|
2022-11-13 09:02:17 +01:00
|
|
|
trait.setRandomlySwitchTargets(randomSwitchTargets);
|
|
|
|
Messaging.sendTr(sender, randomSwitchTargets ? Messages.LOOKCLOSE_RANDOM_TARGET_SWITCH_ENABLED
|
|
|
|
: Messages.LOOKCLOSE_RANDOM_TARGET_SWITCH_DISABLED, npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-12-27 07:22:27 +01:00
|
|
|
if (targetNPCs != null) {
|
|
|
|
trait.setTargetNPCs(targetNPCs);
|
|
|
|
Messaging.sendTr(sender,
|
|
|
|
targetNPCs ? Messages.LOOKCLOSE_TARGET_NPCS_SET : Messages.LOOKCLOSE_TARGET_NPCS_UNSET,
|
|
|
|
npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-11-13 09:02:17 +01:00
|
|
|
if (disableWhenNavigating != null) {
|
|
|
|
trait.setDisableWhileNavigating(disableWhenNavigating);
|
|
|
|
Messaging.sendTr(sender, disableWhenNavigating ? Messages.LOOKCLOSE_DISABLE_WHEN_NAVIGATING
|
|
|
|
: Messages.LOOKCLOSE_ENABLE_WHEN_NAVIGATING, npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (range != null) {
|
|
|
|
trait.setRange(range);
|
2023-07-29 17:26:02 +02:00
|
|
|
Messaging.sendTr(sender, Messages.LOOKCLOSE_RANGE_SET, npc.getName(), range);
|
2022-04-16 16:49:20 +02:00
|
|
|
toggle = false;
|
|
|
|
}
|
|
|
|
if (args.hasFlag('r')) {
|
|
|
|
trait.setRealisticLooking(!trait.useRealisticLooking());
|
|
|
|
Messaging.sendTr(sender, trait.useRealisticLooking() ? Messages.LOOKCLOSE_REALISTIC_LOOK_SET
|
|
|
|
: Messages.LOOKCLOSE_REALISTIC_LOOK_UNSET, npc.getName());
|
|
|
|
toggle = false;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (randomLookDelay != null) {
|
2023-03-12 15:29:41 +01:00
|
|
|
trait.setRandomLookDelay(Math.max(1, Util.toTicks(randomLookDelay)));
|
2023-04-25 17:56:50 +02:00
|
|
|
Messaging.sendTr(sender, Messages.LOOKCLOSE_RANDOM_DELAY_SET, npc.getName(), Util.toTicks(randomLookDelay));
|
2019-04-26 15:14:15 +02:00
|
|
|
toggle = false;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (randomPitch != null) {
|
2019-04-26 15:14:15 +02:00
|
|
|
try {
|
2022-09-06 20:11:07 +02:00
|
|
|
String[] parts = randomPitch.split(",");
|
2019-04-26 15:14:15 +02:00
|
|
|
float min = Float.parseFloat(parts[0]), max = Float.parseFloat(parts[1]);
|
|
|
|
if (min > max)
|
|
|
|
throw new IllegalArgumentException();
|
2022-04-16 16:49:20 +02:00
|
|
|
trait.setRandomLookPitchRange(min, max);
|
2019-04-26 15:14:15 +02:00
|
|
|
} catch (Exception e) {
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messaging.tr(Messages.ERROR_SETTING_LOOKCLOSE_RANGE, randomPitch));
|
2019-04-26 15:14:15 +02:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
Messaging.sendTr(sender, Messages.LOOKCLOSE_RANDOM_PITCH_RANGE_SET, npc.getName(), randomPitch);
|
2019-04-26 15:14:15 +02:00
|
|
|
toggle = false;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (randomYaw != null) {
|
2019-04-26 15:14:15 +02:00
|
|
|
try {
|
2022-09-06 20:11:07 +02:00
|
|
|
String[] parts = randomYaw.split(",");
|
2019-04-26 15:14:15 +02:00
|
|
|
float min = Float.parseFloat(parts[0]), max = Float.parseFloat(parts[1]);
|
|
|
|
if (min > max)
|
|
|
|
throw new IllegalArgumentException();
|
2022-04-16 16:49:20 +02:00
|
|
|
trait.setRandomLookYawRange(min, max);
|
2019-04-26 15:14:15 +02:00
|
|
|
} catch (Exception e) {
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messaging.tr(Messages.ERROR_SETTING_LOOKCLOSE_RANGE, randomYaw));
|
2019-04-26 15:14:15 +02:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
Messaging.sendTr(sender, Messages.LOOKCLOSE_RANDOM_YAW_RANGE_SET, npc.getName(), randomYaw);
|
2019-04-26 15:14:15 +02:00
|
|
|
toggle = false;
|
|
|
|
}
|
|
|
|
if (toggle) {
|
2022-04-16 16:49:20 +02:00
|
|
|
Messaging.sendTr(sender, trait.toggle() ? Messages.LOOKCLOSE_SET : Messages.LOOKCLOSE_STOPPED,
|
2019-04-26 15:14:15 +02:00
|
|
|
npc.getName());
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "metadata set|get|remove [key] (value) (-t(emporary))",
|
|
|
|
desc = "Manages NPC metadata",
|
|
|
|
modifiers = { "metadata" },
|
|
|
|
flags = "t",
|
2022-10-02 17:10:23 +02:00
|
|
|
min = 3,
|
2020-02-14 15:48:40 +01:00
|
|
|
max = 4,
|
|
|
|
permission = "citizens.npc.metadata")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2022-09-07 21:01:39 +02:00
|
|
|
public void metadata(CommandContext args, CommandSender sender, NPC npc,
|
2023-03-25 16:22:46 +01:00
|
|
|
@Arg(value = 1, completions = { "set", "get", "remove" }) String command, @Arg(2) NPC.Metadata enumKey)
|
|
|
|
throws CommandException {
|
2022-01-17 08:45:04 +01:00
|
|
|
String key = args.getString(2);
|
2022-01-20 10:10:52 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (command.equals("set")) {
|
|
|
|
if (args.argsLength() != 4)
|
|
|
|
throw new CommandException();
|
2022-01-17 08:45:04 +01:00
|
|
|
|
|
|
|
Object metadata = args.getString(3);
|
|
|
|
if (metadata.equals("false") || metadata.equals("true")) {
|
|
|
|
metadata = Boolean.parseBoolean(args.getString(3));
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
metadata = Integer.parseInt(args.getString(3));
|
|
|
|
} catch (NumberFormatException nfe) {
|
|
|
|
try {
|
|
|
|
metadata = Double.parseDouble(args.getString(3));
|
|
|
|
} catch (NumberFormatException nfe2) {
|
|
|
|
}
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('t')) {
|
2023-03-25 16:22:46 +01:00
|
|
|
if (enumKey != null) {
|
|
|
|
npc.data().set(enumKey, metadata);
|
|
|
|
} else {
|
|
|
|
npc.data().set(key, metadata);
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
} else if (enumKey != null) {
|
|
|
|
npc.data().setPersistent(enumKey, metadata);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-11-05 13:58:37 +01:00
|
|
|
npc.data().setPersistent(key, metadata);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2023-04-27 12:55:42 +02:00
|
|
|
Messaging.sendTr(sender, Messages.METADATA_SET, enumKey != null ? enumKey : key, args.getString(3));
|
2019-12-23 03:03:08 +01:00
|
|
|
} else if (command.equals("get")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() != 3)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException();
|
2023-04-27 12:55:42 +02:00
|
|
|
Object data = enumKey != null ? npc.data().get(enumKey) : npc.data().get(key);
|
|
|
|
if (data == null) {
|
|
|
|
data = "null";
|
|
|
|
}
|
|
|
|
sender.sendMessage(data.toString());
|
2019-12-23 03:03:08 +01:00
|
|
|
} else if (command.equals("remove")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() != 3)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException();
|
2023-03-25 16:22:46 +01:00
|
|
|
if (enumKey != null) {
|
|
|
|
npc.data().remove(enumKey);
|
|
|
|
} else {
|
|
|
|
npc.data().remove(key);
|
|
|
|
}
|
2023-04-27 12:55:42 +02:00
|
|
|
Messaging.sendTr(sender, Messages.METADATA_UNSET, enumKey != null ? enumKey : key, npc.getName());
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-01-17 08:45:04 +01:00
|
|
|
throw new CommandUsageException();
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "minecart (--item item_name(:data)) (--offset offset)",
|
|
|
|
desc = "Sets minecart item",
|
|
|
|
modifiers = { "minecart" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "",
|
|
|
|
permission = "citizens.npc.minecart")
|
|
|
|
@Requirements(
|
|
|
|
selected = true,
|
|
|
|
ownership = true,
|
|
|
|
types = { EntityType.MINECART, EntityType.MINECART_CHEST, EntityType.MINECART_COMMAND,
|
|
|
|
EntityType.MINECART_FURNACE, EntityType.MINECART_HOPPER, EntityType.MINECART_MOB_SPAWNER,
|
|
|
|
EntityType.MINECART_TNT })
|
2022-09-06 20:11:07 +02:00
|
|
|
public void minecart(CommandContext args, CommandSender sender, NPC npc, @Flag("item") String item)
|
|
|
|
throws CommandException {
|
|
|
|
if (item != null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
int data = 0;
|
2022-09-06 20:11:07 +02:00
|
|
|
if (item.contains(":")) {
|
|
|
|
int dataIndex = item.indexOf(':');
|
|
|
|
data = Integer.parseInt(item.substring(dataIndex + 1));
|
|
|
|
item = item.substring(0, dataIndex);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
Material material = Material.matchMaterial(item);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (material == null)
|
|
|
|
throw new CommandException();
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.MINECART_ITEM, material.name());
|
|
|
|
npc.data().setPersistent(NPC.Metadata.MINECART_ITEM_DATA, data);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("offset")) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.MINECART_OFFSET, args.getFlagInteger("offset"));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2023-01-01 08:26:35 +01:00
|
|
|
Messaging.sendTr(sender, Messages.MINECART_SET, npc.data().get(NPC.Metadata.MINECART_ITEM, ""),
|
|
|
|
npc.data().get(NPC.Metadata.MINECART_ITEM_DATA, 0), npc.data().get(NPC.Metadata.MINECART_OFFSET, 0));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-12-24 18:37:54 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
modifiers = { "mirror" },
|
2023-02-11 15:52:53 +01:00
|
|
|
usage = "mirror --name [true|false]",
|
2022-12-24 18:37:54 +01:00
|
|
|
desc = "Controls mirroring of NPC skins and more",
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.mirror")
|
|
|
|
@Requirements(selected = true, ownership = true)
|
2023-12-21 19:21:18 +01:00
|
|
|
public void mirror(CommandContext args, CommandSender sender, NPC npc, @Flag("name") Boolean name)
|
|
|
|
throws CommandException {
|
|
|
|
if (protocolListener == null)
|
|
|
|
throw new CommandException("ProtocolLib must be enabled to use this feature");
|
|
|
|
|
2022-12-24 18:37:54 +01:00
|
|
|
MirrorTrait trait = npc.getOrAddTrait(MirrorTrait.class);
|
2023-02-11 15:52:53 +01:00
|
|
|
if (name != null) {
|
|
|
|
trait.setEnabled(true);
|
|
|
|
trait.setMirrorName(name);
|
|
|
|
Messaging.sendTr(sender, name ? Messages.MIRROR_NAME_SET : Messages.MIRROR_NAME_UNSET, npc.getName());
|
|
|
|
} else {
|
|
|
|
boolean enabled = !trait.isEnabled();
|
|
|
|
trait.setEnabled(enabled);
|
|
|
|
Messaging.sendTr(sender, enabled ? Messages.MIRROR_SET : Messages.MIRROR_UNSET, npc.getName());
|
|
|
|
}
|
2022-12-24 18:37:54 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-11-04 19:03:57 +01:00
|
|
|
usage = "mount (--onnpc <npc id|uuid>) (-c(ancel))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Mounts a controllable NPC",
|
|
|
|
modifiers = { "mount" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "c",
|
|
|
|
permission = "citizens.npc.mount")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void mount(CommandContext args, CommandSender sender, NPC npc, @Flag("onnpc") String onnpc)
|
|
|
|
throws CommandException {
|
|
|
|
if (onnpc != null) {
|
2017-12-30 08:36:36 +01:00
|
|
|
NPC mount;
|
|
|
|
try {
|
2022-09-06 20:11:07 +02:00
|
|
|
UUID uuid = UUID.fromString(onnpc);
|
2017-12-30 08:36:36 +01:00
|
|
|
mount = CitizensAPI.getNPCRegistry().getByUniqueId(uuid);
|
|
|
|
} catch (IllegalArgumentException ex) {
|
|
|
|
mount = CitizensAPI.getNPCRegistry().getById(args.getFlagInteger("onnpc"));
|
|
|
|
}
|
2023-11-04 19:03:57 +01:00
|
|
|
if (mount == null || !mount.isSpawned())
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messaging.tr(Messages.MOUNT_NPC_MUST_BE_SPAWNED, onnpc));
|
2023-11-04 19:03:57 +01:00
|
|
|
|
|
|
|
if (mount.equals(npc))
|
2020-07-27 04:44:13 +02:00
|
|
|
throw new CommandException(Messages.TRIED_TO_MOUNT_NPC_ON_ITSELF);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
NMS.mount(mount.getEntity(), npc.getEntity());
|
|
|
|
return;
|
2023-11-04 19:03:57 +01:00
|
|
|
}
|
|
|
|
if (args.hasFlag('c')) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(MountTrait.class).unmount();
|
2019-03-01 13:50:44 +01:00
|
|
|
return;
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-09-14 11:57:58 +02:00
|
|
|
boolean enabled = npc.hasTrait(Controllable.class) && npc.getOrAddTrait(Controllable.class).isEnabled();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!enabled) {
|
2018-03-19 08:02:07 +01:00
|
|
|
Messaging.sendTr(sender, Messages.NPC_NOT_CONTROLLABLE, npc.getName());
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2023-11-04 19:03:57 +01:00
|
|
|
if (!(sender instanceof Player))
|
2018-03-19 08:02:07 +01:00
|
|
|
throw new CommandException(CommandMessages.MUST_BE_INGAME);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2018-03-19 08:02:07 +01:00
|
|
|
Player player = (Player) sender;
|
2020-09-14 11:57:58 +02:00
|
|
|
boolean success = npc.getOrAddTrait(Controllable.class).mount(player);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!success) {
|
|
|
|
Messaging.sendTr(player, Messages.FAILED_TO_MOUNT_NPC, npc.getName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "moveto x:y:z:world | x y z world",
|
|
|
|
desc = "Teleports a NPC to a given location",
|
|
|
|
modifiers = "moveto",
|
|
|
|
min = 1,
|
2022-09-07 21:01:39 +02:00
|
|
|
valueFlags = { "x", "y", "z", "yaw", "pitch", "world" },
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.moveto")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void moveto(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
if (!npc.isSpawned()) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.spawn(npc.getOrAddTrait(CurrentLocation.class).getLocation(), SpawnReason.COMMAND);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!npc.isSpawned())
|
2023-01-01 08:26:35 +01:00
|
|
|
throw new CommandException("NPC could not be spawned.");
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
Location current = npc.getEntity().getLocation();
|
|
|
|
Location to;
|
|
|
|
if (args.argsLength() > 1) {
|
|
|
|
String[] parts = Iterables.toArray(Splitter.on(':').split(args.getJoinedStrings(1, ':')), String.class);
|
|
|
|
if (parts.length != 4 && parts.length != 3)
|
|
|
|
throw new CommandException(Messages.MOVETO_FORMAT);
|
|
|
|
double x = Double.parseDouble(parts[0]);
|
|
|
|
double y = Double.parseDouble(parts[1]);
|
|
|
|
double z = Double.parseDouble(parts[2]);
|
|
|
|
World world = parts.length == 4 ? Bukkit.getWorld(parts[3]) : current.getWorld();
|
|
|
|
if (world == null)
|
|
|
|
throw new CommandException(Messages.WORLD_NOT_FOUND);
|
|
|
|
to = new Location(world, x, y, z, current.getYaw(), current.getPitch());
|
|
|
|
} else {
|
|
|
|
to = current.clone();
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.hasValueFlag("x")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
to.setX(args.getFlagDouble("x"));
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("y")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
to.setY(args.getFlagDouble("y"));
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("z")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
to.setZ(args.getFlagDouble("z"));
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("yaw")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
to.setYaw((float) args.getFlagDouble("yaw"));
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
|
|
|
if (args.hasValueFlag("pitch")) {
|
2017-12-30 08:36:36 +01:00
|
|
|
to.setPitch((float) args.getFlagDouble("pitch"));
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasValueFlag("world")) {
|
|
|
|
World world = Bukkit.getWorld(args.getFlag("world"));
|
|
|
|
if (world == null)
|
|
|
|
throw new CommandException(Messages.WORLD_NOT_FOUND);
|
|
|
|
to.setWorld(world);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
npc.teleport(to, TeleportCause.COMMAND);
|
2019-03-28 15:46:26 +01:00
|
|
|
NMS.look(npc.getEntity(), to.getYaw(), to.getPitch());
|
2020-03-31 15:44:04 +02:00
|
|
|
Messaging.sendTr(sender, Messages.MOVETO_TELEPORTED, npc.getName(), Util.prettyPrintLocation(to));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-10-22 04:42:44 +02:00
|
|
|
modifiers = { "name", "hidename" },
|
2021-03-13 15:17:55 +01:00
|
|
|
usage = "name (-h(over))",
|
|
|
|
desc = "Toggle nameplate visibility, or only show names on hover",
|
2020-02-14 15:48:40 +01:00
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "h",
|
|
|
|
permission = "citizens.npc.name")
|
2021-05-06 19:48:22 +02:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void name(CommandContext args, CommandSender sender, NPC npc) {
|
2022-03-23 13:57:18 +01:00
|
|
|
String old = npc.data().<Object> get(NPC.Metadata.NAMEPLATE_VISIBLE, true).toString();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('h')) {
|
|
|
|
old = "hover";
|
|
|
|
} else {
|
|
|
|
old = old.equals("hover") ? "true" : "" + !Boolean.parseBoolean(old);
|
|
|
|
}
|
2022-03-23 13:57:18 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.NAMEPLATE_VISIBLE, old);
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.scheduleUpdate(NPCUpdate.PACKET);
|
2022-08-17 17:33:29 +02:00
|
|
|
Messaging.sendTr(sender, Messages.NAMEPLATE_VISIBILITY_SET, old);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Command(aliases = { "npc" }, desc = "Show basic NPC information", max = 0, permission = "citizens.npc.info")
|
2023-11-05 13:58:37 +01:00
|
|
|
public void npc(CommandContext args, CommandSender sender, NPC npc) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.send(sender, StringHelper.wrapHeader(npc.getName()));
|
2022-10-05 16:27:09 +02:00
|
|
|
Messaging.send(sender, " ID: [[" + npc.getId());
|
2021-01-03 17:18:34 +01:00
|
|
|
EntityType type = npc.getOrAddTrait(MobType.class).getType();
|
2023-05-03 19:51:48 +02:00
|
|
|
Messaging.send(sender, " UUID: [[" + npc.getUniqueId());
|
2022-10-05 16:27:09 +02:00
|
|
|
Messaging.send(sender, " Type: [[" + type);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc.isSpawned()) {
|
|
|
|
Location loc = npc.getEntity().getLocation();
|
2023-05-03 19:51:48 +02:00
|
|
|
String format = " Spawned at [[%d, %d, %d, %.2f, %.2f (head %.2f)]] [[%s";
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.send(sender,
|
2023-05-03 19:51:48 +02:00
|
|
|
String.format(format, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(),
|
|
|
|
NMS.getYaw(npc.getEntity()), loc.getPitch(), NMS.getHeadYaw(npc.getEntity()),
|
|
|
|
loc.getWorld().getName()));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-10-05 16:27:09 +02:00
|
|
|
Messaging.send(sender, " Traits");
|
2017-12-30 08:36:36 +01:00
|
|
|
for (Trait trait : npc.getTraits()) {
|
2023-05-03 19:51:48 +02:00
|
|
|
String message = " - [[" + trait.getName();
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.send(sender, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "ocelot (--type type) (-s(itting), -n(ot sitting))",
|
|
|
|
desc = "Set the ocelot type of an NPC and whether it is sitting",
|
|
|
|
modifiers = { "ocelot" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
requiresFlags = true,
|
|
|
|
flags = "sn",
|
|
|
|
permission = "citizens.npc.ocelot")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.OCELOT })
|
2022-09-06 20:11:07 +02:00
|
|
|
public void ocelot(CommandContext args, CommandSender sender, NPC npc, @Flag("type") Ocelot.Type type)
|
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
OcelotModifiers trait = npc.getOrAddTrait(OcelotModifiers.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('s')) {
|
|
|
|
trait.setSitting(true);
|
|
|
|
} else if (args.hasFlag('n')) {
|
|
|
|
trait.setSitting(false);
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("type")) {
|
|
|
|
if (type == null) {
|
|
|
|
String valid = Util.listValuesPretty(Ocelot.Type.values());
|
|
|
|
throw new CommandException(Messages.INVALID_OCELOT_TYPE, valid);
|
|
|
|
}
|
|
|
|
trait.setType(type);
|
2020-05-07 10:29:45 +02:00
|
|
|
if (!trait.supportsOcelotType()) {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.OCELOT_TYPE_DEPRECATED);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-07 21:01:39 +02:00
|
|
|
usage = "owner [uuid|SERVER]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Set the owner of an NPC",
|
|
|
|
modifiers = { "owner" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.owner")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void owner(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
Owner ownerTrait = npc.getOrAddTrait(Owner.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.argsLength() == 1) {
|
2023-09-20 16:05:05 +02:00
|
|
|
Messaging.sendTr(sender, Messages.NPC_OWNER, npc.getName(), ownerTrait.getOwner());
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
|
|
|
}
|
2021-10-20 12:40:49 +02:00
|
|
|
OfflinePlayer p;
|
2021-10-13 11:56:22 +02:00
|
|
|
UUID uuid;
|
2021-10-20 12:40:49 +02:00
|
|
|
if (args.getString(1).equalsIgnoreCase("SERVER")) {
|
|
|
|
uuid = null;
|
2022-02-11 11:46:11 +01:00
|
|
|
} else if ((p = Bukkit.getOfflinePlayer(args.getString(1))).hasPlayedBefore() || p.isOnline()) {
|
2021-10-13 11:56:22 +02:00
|
|
|
uuid = p.getUniqueId();
|
|
|
|
} else {
|
2021-10-20 12:40:49 +02:00
|
|
|
uuid = UUID.fromString(args.getString(1));
|
2021-10-13 11:56:22 +02:00
|
|
|
}
|
2021-10-12 14:42:57 +02:00
|
|
|
if (ownerTrait.isOwnedBy(uuid))
|
|
|
|
throw new CommandException(Messages.ALREADY_OWNER, uuid, npc.getName());
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2021-10-12 14:42:57 +02:00
|
|
|
ownerTrait.setOwner(uuid);
|
|
|
|
boolean serverOwner = uuid == null;
|
|
|
|
Messaging.sendTr(sender, serverOwner ? Messages.OWNER_SET_SERVER : Messages.OWNER_SET, npc.getName(), uuid);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-03-02 16:08:03 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "packet --enabled [true|false]",
|
|
|
|
desc = "Controls packet NPC settings",
|
|
|
|
modifiers = { "packet" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.packet")
|
|
|
|
@Requirements(selected = true, ownership = true)
|
|
|
|
public void packet(CommandContext args, CommandSender sender, NPC npc, @Flag("enabled") Boolean explicit)
|
|
|
|
throws CommandException {
|
2023-03-05 17:28:44 +01:00
|
|
|
if (explicit == null) {
|
|
|
|
explicit = !npc.hasTrait(PacketNPC.class);
|
|
|
|
}
|
|
|
|
if (explicit) {
|
|
|
|
npc.getOrAddTrait(PacketNPC.class);
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_PACKET_ENABLED, npc.getName());
|
|
|
|
} else {
|
|
|
|
npc.removeTrait(PacketNPC.class);
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_PACKET_DISABLED, npc.getName());
|
2023-03-02 16:08:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-07 20:35:55 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "painting (--art art)",
|
|
|
|
desc = "Set painting modifiers",
|
|
|
|
modifiers = { "painting" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.painting")
|
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.PAINTING })
|
|
|
|
public void painting(CommandContext args, CommandSender sender, NPC npc, @Flag("art") Art art)
|
|
|
|
throws CommandException {
|
|
|
|
PaintingTrait trait = npc.getOrAddTrait(PaintingTrait.class);
|
|
|
|
if (art != null) {
|
|
|
|
trait.setArt(art);
|
|
|
|
Messaging.sendTr(sender, Messages.PAINTING_ART_SET, npc.getName(), Util.prettyEnum(art));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw new CommandUsageException();
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "passive (--set [true|false])",
|
|
|
|
desc = "Sets whether an NPC damages other entities or not",
|
|
|
|
modifiers = { "passive" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.passive")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void passive(CommandContext args, CommandSender sender, NPC npc, @Flag("set") Boolean set)
|
|
|
|
throws CommandException {
|
2023-01-01 08:26:35 +01:00
|
|
|
boolean passive = set != null ? set : !npc.data().get(NPC.Metadata.DAMAGE_OTHERS, true);
|
|
|
|
npc.data().setPersistent(NPC.Metadata.DAMAGE_OTHERS, passive);
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, passive ? Messages.PASSIVE_SET : Messages.PASSIVE_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-03-05 17:28:44 +01:00
|
|
|
usage = "pathopt --avoid-water|aw [true|false] --stationary-ticks [ticks] --attack-range [range] --distance-margin [margin] --path-distance-margin [margin] --use-new-finder [true|false] --falling-distance [distance]",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets an NPC's pathfinding options",
|
|
|
|
modifiers = { "pathopt", "po", "patho" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.pathfindingoptions")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void pathfindingOptions(CommandContext args, CommandSender sender, NPC npc,
|
2023-03-12 15:29:41 +01:00
|
|
|
@Flag("avoid-water") Boolean avoidwater, @Flag("open-doors") Boolean opendoors,
|
|
|
|
@Flag("stationary-ticks") Integer stationaryTicks, @Flag("distance-margin") Double distanceMargin,
|
|
|
|
@Flag("path-distance-margin") Double pathDistanceMargin, @Flag("attack-range") Double attackRange,
|
|
|
|
@Flag("use-new-finder") Boolean useNewFinder, @Flag("falling-distance") Integer fallingDistance)
|
|
|
|
throws CommandException {
|
2020-05-05 12:40:58 +02:00
|
|
|
String output = "";
|
2022-09-06 20:11:07 +02:00
|
|
|
if (avoidwater != null) {
|
|
|
|
npc.getNavigator().getDefaultParameters().avoidWater(avoidwater);
|
|
|
|
output += Messaging.tr(avoidwater ? Messages.PATHFINDING_OPTIONS_AVOID_WATER_SET
|
2017-12-30 08:36:36 +01:00
|
|
|
: Messages.PATHFINDING_OPTIONS_AVOID_WATER_UNSET, npc.getName());
|
|
|
|
}
|
2023-03-12 15:29:41 +01:00
|
|
|
if (opendoors != null) {
|
|
|
|
npc.data().setPersistent(NPC.Metadata.PATHFINDER_OPEN_DOORS, opendoors);
|
|
|
|
output += Messaging.tr(opendoors ? Messages.PATHFINDING_OPTIONS_OPEN_DOORS_SET
|
|
|
|
: Messages.PATHFINDING_OPTIONS_OPEN_DOORS_UNSET, npc.getName());
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (stationaryTicks != null) {
|
|
|
|
if (stationaryTicks < 0)
|
2020-05-05 12:40:58 +02:00
|
|
|
throw new CommandUsageException();
|
2022-09-06 20:11:07 +02:00
|
|
|
npc.getNavigator().getDefaultParameters().stationaryTicks(stationaryTicks);
|
2023-03-12 15:29:41 +01:00
|
|
|
output += " "
|
|
|
|
+ Messaging.tr(Messages.PATHFINDING_OPTIONS_STATIONARY_TICKS_SET, npc.getName(), stationaryTicks);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (distanceMargin != null) {
|
|
|
|
if (distanceMargin < 0)
|
2020-05-05 12:40:58 +02:00
|
|
|
throw new CommandUsageException();
|
2022-09-06 20:11:07 +02:00
|
|
|
npc.getNavigator().getDefaultParameters().distanceMargin(distanceMargin);
|
2023-03-12 15:29:41 +01:00
|
|
|
output += " "
|
|
|
|
+ Messaging.tr(Messages.PATHFINDING_OPTIONS_DISTANCE_MARGIN_SET, npc.getName(), distanceMargin);
|
2020-05-05 12:40:58 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (pathDistanceMargin != null) {
|
|
|
|
if (pathDistanceMargin < 0)
|
2020-05-05 12:40:58 +02:00
|
|
|
throw new CommandUsageException();
|
2022-09-06 20:11:07 +02:00
|
|
|
npc.getNavigator().getDefaultParameters().pathDistanceMargin(pathDistanceMargin);
|
2023-03-12 15:29:41 +01:00
|
|
|
output += " " + Messaging.tr(Messages.PATHFINDING_OPTIONS_PATH_DISTANCE_MARGIN_SET, npc.getName(),
|
2022-09-06 20:11:07 +02:00
|
|
|
pathDistanceMargin);
|
2019-04-26 12:10:23 +02:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (attackRange != null) {
|
|
|
|
if (attackRange < 0)
|
2020-05-05 12:40:58 +02:00
|
|
|
throw new CommandUsageException();
|
2022-09-06 20:11:07 +02:00
|
|
|
npc.getNavigator().getDefaultParameters().attackRange(attackRange);
|
2023-03-12 15:29:41 +01:00
|
|
|
output += " " + Messaging.tr(Messages.PATHFINDING_OPTIONS_ATTACK_RANGE_SET, npc.getName(), attackRange);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (useNewFinder != null) {
|
|
|
|
npc.getNavigator().getDefaultParameters().useNewPathfinder(useNewFinder);
|
2023-03-12 15:29:41 +01:00
|
|
|
output += " " + Messaging.tr(Messages.PATHFINDING_OPTIONS_USE_NEW_FINDER, npc.getName(), useNewFinder);
|
2020-05-05 12:40:58 +02:00
|
|
|
}
|
2023-03-05 17:28:44 +01:00
|
|
|
if (fallingDistance != null) {
|
2023-03-12 15:29:41 +01:00
|
|
|
npc.data().set(NPC.Metadata.PATHFINDER_FALL_DISTANCE, fallingDistance);
|
|
|
|
output += " "
|
|
|
|
+ Messaging.tr(Messages.PATHFINDING_OPTIONS_FALLING_DISTANCE_SET, npc.getName(), fallingDistance);
|
2023-03-05 17:28:44 +01:00
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
if (output.isEmpty())
|
2020-05-05 12:40:58 +02:00
|
|
|
throw new CommandUsageException();
|
2023-11-05 13:58:37 +01:00
|
|
|
else {
|
2023-03-12 15:29:41 +01:00
|
|
|
Messaging.send(sender, output.trim());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "pathrange [range]",
|
|
|
|
desc = "Sets an NPC's pathfinding range",
|
|
|
|
modifiers = { "pathrange", "pathfindingrange", "prange" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.pathfindingrange")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void pathfindingRange(CommandContext args, CommandSender sender, NPC npc) {
|
|
|
|
double range = Math.max(1, args.getDouble(1));
|
|
|
|
npc.getNavigator().getDefaultParameters().range((float) range);
|
|
|
|
Messaging.sendTr(sender, Messages.PATHFINDING_RANGE_SET, range);
|
|
|
|
}
|
|
|
|
|
2020-09-17 17:31:44 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-10-01 11:27:38 +02:00
|
|
|
usage = "pathto me | here | cursor | [x] [y] [z] (--margin [distance margin])",
|
2020-09-17 17:31:44 +02:00
|
|
|
desc = "Starts pathfinding to a certain location",
|
|
|
|
modifiers = { "pathto" },
|
2022-05-06 15:25:12 +02:00
|
|
|
min = 2,
|
2020-09-17 17:31:44 +02:00
|
|
|
max = 4,
|
|
|
|
permission = "citizens.npc.pathto")
|
2022-09-07 21:01:39 +02:00
|
|
|
public void pathto(CommandContext args, CommandSender sender, NPC npc,
|
2023-10-01 11:27:38 +02:00
|
|
|
@Arg(value = 1, completions = { "me", "here", "cursor" }) String option, @Flag("margin") Double margin)
|
|
|
|
throws CommandException {
|
2020-09-17 17:31:44 +02:00
|
|
|
Location loc = npc.getStoredLocation();
|
2022-05-06 15:25:12 +02:00
|
|
|
if (args.argsLength() == 2) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (option.equalsIgnoreCase("me") || option.equalsIgnoreCase("here")) {
|
2022-05-06 15:25:12 +02:00
|
|
|
loc = args.getSenderLocation();
|
2022-09-07 21:01:39 +02:00
|
|
|
} else if (option.equalsIgnoreCase("cursor")) {
|
2022-05-06 15:25:12 +02:00
|
|
|
loc = ((Player) sender).getTargetBlockExact(32).getLocation();
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-05-06 15:25:12 +02:00
|
|
|
throw new CommandUsageException();
|
|
|
|
} else {
|
|
|
|
loc.setX(args.getDouble(1));
|
|
|
|
loc.setY(args.getDouble(2));
|
|
|
|
loc.setZ(args.getDouble(3));
|
|
|
|
}
|
2020-09-17 17:31:44 +02:00
|
|
|
npc.getNavigator().setTarget(loc);
|
2023-10-01 11:27:38 +02:00
|
|
|
if (margin != null) {
|
|
|
|
npc.getNavigator().getLocalParameters().distanceMargin(margin);
|
|
|
|
}
|
2020-09-17 17:31:44 +02:00
|
|
|
}
|
|
|
|
|
2023-02-21 16:59:33 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-02-28 17:21:08 +01:00
|
|
|
usage = "pausepathfinding --onrightclick [true|false] --when-player-within [range in blocks] --pauseticks [ticks]",
|
2023-02-21 16:59:33 +01:00
|
|
|
desc = "Sets pathfinding pause",
|
|
|
|
modifiers = { "pausepathfinding" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.pausepathfinding")
|
|
|
|
public void pausepathfinding(CommandContext args, CommandSender sender, NPC npc,
|
2023-02-28 17:21:08 +01:00
|
|
|
@Flag("onrightclick") Boolean rightclick, @Flag("when-player-within") Double playerRange,
|
2023-02-21 16:59:33 +01:00
|
|
|
@Flag("pauseticks") Integer ticks) throws CommandException {
|
|
|
|
PausePathfindingTrait trait = npc.getOrAddTrait(PausePathfindingTrait.class);
|
|
|
|
if (playerRange != null) {
|
|
|
|
if (playerRange <= 0)
|
|
|
|
throw new CommandException("Invalid range");
|
|
|
|
trait.setPlayerRangeBlocks(playerRange);
|
|
|
|
Messaging.sendTr(sender, Messages.PAUSEPATHFINDING_RANGE_SET, npc.getName(), playerRange);
|
|
|
|
}
|
|
|
|
if (rightclick != null) {
|
|
|
|
trait.setRightClick(rightclick);
|
|
|
|
Messaging.sendTr(sender,
|
2023-11-04 19:03:57 +01:00
|
|
|
rightclick ? Messages.PAUSEPATHFINDING_RIGHTCLICK_SET : Messages.PAUSEPATHFINDING_RIGHTCLICK_UNSET,
|
2023-02-21 16:59:33 +01:00
|
|
|
npc.getName());
|
|
|
|
}
|
|
|
|
if (ticks != null) {
|
|
|
|
trait.setPauseTicks(ticks);
|
|
|
|
Messaging.sendTr(sender, Messages.PAUSEPATHFINDING_TICKS_SET, npc.getName(), ticks);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-21 17:13:51 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "pickupitems (--set [true|false])",
|
|
|
|
desc = "Allow NPC to pick up items",
|
|
|
|
modifiers = { "pickupitems" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.pickupitems")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void pickupitems(CommandContext args, CommandSender sender, NPC npc, @Flag("set") Boolean set)
|
|
|
|
throws CommandException {
|
|
|
|
boolean pickup = set == null ? !npc.data().get(NPC.Metadata.PICKUP_ITEMS, !npc.isProtected()) : set;
|
2022-11-11 15:41:34 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.PICKUP_ITEMS, pickup);
|
2022-11-10 14:31:32 +01:00
|
|
|
Messaging.sendTr(sender, pickup ? Messages.PICKUP_ITEMS_SET : Messages.PICKUP_ITEMS_UNSET, npc.getName());
|
2022-07-21 17:13:51 +02:00
|
|
|
}
|
|
|
|
|
2022-04-19 09:50:52 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "panimate [animation]",
|
|
|
|
desc = "Plays a player animation",
|
|
|
|
modifiers = { "panimate" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.panimate")
|
|
|
|
@Requirements(selected = true, ownership = true, types = EntityType.PLAYER)
|
2022-09-07 21:01:39 +02:00
|
|
|
public void playerAnimate(CommandContext args, CommandSender sender, NPC npc, @Arg(1) PlayerAnimation animation)
|
|
|
|
throws CommandException {
|
2022-04-19 09:50:52 +02:00
|
|
|
if (animation == null) {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.UNKNOWN_PLAYER_ANIMATION,
|
|
|
|
Util.listValuesPretty(PlayerAnimation.values()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
animation.play((Player) npc.getEntity(), 64);
|
|
|
|
}
|
|
|
|
|
2023-03-07 16:58:03 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-11-05 13:58:37 +01:00
|
|
|
usage = "playerfilter -a(llowlist) -e(mpty) -d(enylist) --add [uuid] --remove [uuid] --addgroup [group] --removegroup [group] -c(lear) --applywithin [blocks range]",
|
2023-03-07 16:58:03 +01:00
|
|
|
desc = "Sets the NPC filter",
|
|
|
|
modifiers = { "playerfilter" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2023-05-11 15:40:01 +02:00
|
|
|
flags = "adce",
|
2023-03-07 16:58:03 +01:00
|
|
|
permission = "citizens.npc.playerfilter")
|
2023-05-11 15:40:01 +02:00
|
|
|
public void playerfilter(CommandContext args, CommandSender sender, NPC npc, @Flag("add") UUID add,
|
2023-11-05 13:58:37 +01:00
|
|
|
@Flag("remove") UUID remove, @Flag("removegroup") String removegroup, @Flag("addgroup") String addgroup,
|
|
|
|
@Flag("applywithin") Double applyRange) {
|
2023-03-07 16:58:03 +01:00
|
|
|
PlayerFilter trait = npc.getOrAddTrait(PlayerFilter.class);
|
2023-05-11 15:40:01 +02:00
|
|
|
if (add != null) {
|
|
|
|
trait.addPlayer(add);
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_PLAYER_ADDED, add, npc.getName());
|
2023-03-07 16:58:03 +01:00
|
|
|
}
|
2023-05-11 15:40:01 +02:00
|
|
|
if (remove != null) {
|
|
|
|
trait.removePlayer(remove);
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_PLAYER_REMOVED, remove, npc.getName());
|
2023-03-07 16:58:03 +01:00
|
|
|
}
|
2023-05-11 15:40:01 +02:00
|
|
|
if (addgroup != null) {
|
|
|
|
trait.addGroup(addgroup);
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_GROUP_ADDED, addgroup, npc.getName());
|
2023-03-07 16:58:03 +01:00
|
|
|
}
|
2023-05-11 15:40:01 +02:00
|
|
|
if (removegroup != null) {
|
|
|
|
trait.removeGroup(removegroup);
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_GROUP_REMOVED, removegroup, npc.getName());
|
2023-03-12 15:29:41 +01:00
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
if (applyRange != null) {
|
|
|
|
trait.setApplyRange(applyRange);
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_APPLYRANGE_SET, npc.getName(), applyRange);
|
|
|
|
}
|
2023-05-11 15:40:01 +02:00
|
|
|
if (args.hasFlag('e')) {
|
|
|
|
trait.setPlayers(Collections.emptySet());
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_EMPTY_SET, npc.getName());
|
|
|
|
}
|
|
|
|
if (args.hasFlag('a')) {
|
|
|
|
trait.setAllowlist();
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_ALLOWLIST_SET, npc.getName());
|
2023-03-12 15:29:41 +01:00
|
|
|
}
|
2023-05-11 15:40:01 +02:00
|
|
|
if (args.hasFlag('d')) {
|
|
|
|
trait.setDenylist();
|
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_DENYLIST_SET, npc.getName());
|
2023-03-12 15:29:41 +01:00
|
|
|
}
|
|
|
|
if (args.hasFlag('c')) {
|
|
|
|
trait.clear();
|
2023-05-11 15:40:01 +02:00
|
|
|
Messaging.sendTr(sender, Messages.PLAYERFILTER_CLEARED, npc.getName());
|
2023-03-12 15:29:41 +01:00
|
|
|
}
|
2023-03-07 16:58:03 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-05-11 15:40:01 +02:00
|
|
|
usage = "playerlist (-a(dd),r(emove))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets whether the NPC is put in the playerlist",
|
|
|
|
modifiers = { "playerlist" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "ar",
|
|
|
|
permission = "citizens.npc.playerlist")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = EntityType.PLAYER)
|
|
|
|
public void playerlist(CommandContext args, CommandSender sender, NPC npc) {
|
2023-01-01 08:26:35 +01:00
|
|
|
boolean remove = !npc.data().get(NPC.Metadata.REMOVE_FROM_PLAYERLIST,
|
2021-12-28 13:13:25 +01:00
|
|
|
Setting.REMOVE_PLAYERS_FROM_PLAYER_LIST.asBoolean());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('a')) {
|
|
|
|
remove = false;
|
|
|
|
} else if (args.hasFlag('r')) {
|
|
|
|
remove = true;
|
|
|
|
}
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.REMOVE_FROM_PLAYERLIST, remove);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc.isSpawned()) {
|
|
|
|
npc.despawn(DespawnReason.PENDING_RESPAWN);
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.spawn(npc.getOrAddTrait(CurrentLocation.class).getLocation(), SpawnReason.RESPAWN);
|
2017-12-30 08:36:36 +01:00
|
|
|
NMS.addOrRemoveFromPlayerList(npc.getEntity(), remove);
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, remove ? Messages.REMOVED_FROM_PLAYERLIST : Messages.ADDED_TO_PLAYERLIST,
|
|
|
|
npc.getName());
|
|
|
|
}
|
|
|
|
|
2023-08-06 12:57:42 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-10-03 17:06:25 +02:00
|
|
|
usage = "playsound [sound] (volume) (pitch) (--at x:y:z:world)",
|
2023-08-06 12:57:42 +02:00
|
|
|
desc = "Plays a sound at the NPC's location",
|
|
|
|
modifiers = { "playsound" },
|
|
|
|
min = 2,
|
|
|
|
max = 4,
|
|
|
|
permission = "citizens.npc.playsound")
|
|
|
|
@Requirements(selected = true, ownership = true)
|
|
|
|
public void playsound(CommandContext args, CommandSender sender, NPC npc, @Arg(1) String sound,
|
2023-10-03 17:06:25 +02:00
|
|
|
@Arg(value = 2, defValue = "1") Float volume, @Arg(value = 3, defValue = "1") Float pitch,
|
|
|
|
@Flag("at") Location at) throws CommandException {
|
|
|
|
Location loc = at == null ? npc.getStoredLocation() : at;
|
|
|
|
loc.getWorld().playSound(loc, sound, volume, pitch);
|
2023-08-06 12:57:42 +02:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-04-25 17:29:22 +02:00
|
|
|
usage = "pose (--save [name] (-d) | --mirror [name] (-d) | --assume [name] | --remove [name] | --default [name]) (--yaw yaw) (--pitch pitch) (-a)",
|
2022-04-24 13:22:55 +02:00
|
|
|
desc = "Manage NPC poses",
|
2020-06-29 09:32:37 +02:00
|
|
|
flags = "ad",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "pose" },
|
|
|
|
min = 1,
|
2023-04-25 17:29:22 +02:00
|
|
|
max = 2,
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.pose")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void pose(CommandContext args, CommandSender sender, NPC npc, @Flag("save") String save,
|
|
|
|
@Flag("mirror") String mirror, @Flag("assume") String assume, @Flag("remove") String remove,
|
2023-04-25 17:29:22 +02:00
|
|
|
@Flag("default") String defaultPose, @Flag("yaw") Float yaw, @Flag("pitch") Float pitch)
|
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
Poses trait = npc.getOrAddTrait(Poses.class);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (save != null) {
|
|
|
|
if (save.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_POSE_NAME);
|
2023-04-25 17:29:22 +02:00
|
|
|
|
2023-04-25 16:23:41 +02:00
|
|
|
Location loc = npc.getStoredLocation();
|
|
|
|
if (yaw != null) {
|
|
|
|
loc.setYaw(yaw);
|
|
|
|
}
|
|
|
|
if (pitch != null) {
|
|
|
|
loc.setPitch(pitch);
|
|
|
|
}
|
2023-04-25 17:29:22 +02:00
|
|
|
if (trait.addPose(save, loc, args.hasFlag('d'))) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.POSE_ADDED);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.POSE_ALREADY_EXISTS, save);
|
|
|
|
} else if (mirror != null) {
|
|
|
|
if (mirror.isEmpty())
|
2022-04-24 13:22:55 +02:00
|
|
|
throw new CommandException(Messages.INVALID_POSE_NAME);
|
|
|
|
|
|
|
|
if (args.getSenderLocation() == null)
|
|
|
|
throw new ServerCommandException();
|
|
|
|
|
2023-04-25 17:29:22 +02:00
|
|
|
if (trait.addPose(mirror, args.getSenderLocation(), args.hasFlag('d'))) {
|
2022-04-24 13:22:55 +02:00
|
|
|
Messaging.sendTr(sender, Messages.POSE_ADDED);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.POSE_ALREADY_EXISTS, mirror);
|
|
|
|
} else if (defaultPose != null) {
|
|
|
|
if (!trait.hasPose(defaultPose))
|
|
|
|
throw new CommandException(Messages.POSE_MISSING, defaultPose);
|
|
|
|
|
|
|
|
trait.setDefaultPose(defaultPose);
|
|
|
|
Messaging.sendTr(sender, Messages.DEFAULT_POSE_SET, defaultPose);
|
|
|
|
} else if (assume != null) {
|
|
|
|
if (assume.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_POSE_NAME);
|
|
|
|
|
2022-09-06 20:11:07 +02:00
|
|
|
if (!trait.hasPose(assume))
|
|
|
|
throw new CommandException(Messages.POSE_MISSING, assume);
|
2022-04-24 13:22:55 +02:00
|
|
|
|
2022-09-06 20:11:07 +02:00
|
|
|
trait.assumePose(assume);
|
|
|
|
} else if (remove != null) {
|
|
|
|
if (remove.isEmpty())
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_POSE_NAME);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (trait.removePose(remove)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.POSE_REMOVED);
|
|
|
|
} else
|
2022-09-06 20:11:07 +02:00
|
|
|
throw new CommandException(Messages.POSE_MISSING, remove);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else if (!args.hasFlag('a')) {
|
|
|
|
trait.describe(sender, args.getInteger(1, 1));
|
|
|
|
}
|
2023-04-25 17:29:22 +02:00
|
|
|
if (args.hasFlag('a')) {
|
|
|
|
if (args.getSenderLocation() == null)
|
|
|
|
throw new ServerCommandException();
|
|
|
|
trait.assumePose(args.getSenderLocation());
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "power",
|
|
|
|
desc = "Toggle a creeper NPC as powered",
|
|
|
|
modifiers = { "power" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.power")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.CREEPER })
|
|
|
|
public void power(CommandContext args, CommandSender sender, NPC npc) {
|
|
|
|
Messaging.sendTr(sender,
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(Powered.class).toggle() ? Messages.POWERED_SET : Messages.POWERED_STOPPED);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "profession|prof [profession]",
|
|
|
|
desc = "Set a NPC's profession",
|
|
|
|
modifiers = { "profession", "prof" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.profession")
|
2018-07-19 14:18:47 +02:00
|
|
|
@Requirements(selected = true, ownership = true)
|
2022-09-07 21:01:39 +02:00
|
|
|
public void profession(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Profession parsed)
|
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
EntityType type = npc.getOrAddTrait(MobType.class).getType();
|
2023-07-03 18:43:58 +02:00
|
|
|
if (type != EntityType.VILLAGER && !type.name().equals("ZOMBIE_VILLAGER"))
|
|
|
|
throw new CommandException(CommandMessages.REQUIREMENTS_INVALID_MOB_TYPE, Util.prettyEnum(type));
|
|
|
|
|
|
|
|
if (parsed == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException(Messages.INVALID_PROFESSION, args.getString(1),
|
2022-01-27 03:48:52 +01:00
|
|
|
Util.listValuesPretty(Profession.values()));
|
2023-07-03 18:43:58 +02:00
|
|
|
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(VillagerProfession.class).setProfession(parsed);
|
2022-09-07 21:01:39 +02:00
|
|
|
Messaging.sendTr(sender, Messages.PROFESSION_SET, npc.getName(), Util.prettyEnum(parsed));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "rabbittype [type]",
|
|
|
|
desc = "Set the Type of a Rabbit NPC",
|
|
|
|
modifiers = { "rabbittype", "rbtype" },
|
|
|
|
min = 2,
|
|
|
|
permission = "citizens.npc.rabbittype")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.RABBIT })
|
2022-09-07 21:01:39 +02:00
|
|
|
public void rabbitType(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Rabbit.Type type)
|
|
|
|
throws CommandException {
|
|
|
|
if (type == null)
|
2022-01-27 03:48:52 +01:00
|
|
|
throw new CommandException(Messages.INVALID_RABBIT_TYPE, Util.listValuesPretty(Rabbit.Type.values()));
|
2022-09-07 21:01:39 +02:00
|
|
|
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getOrAddTrait(RabbitType.class).setType(type);
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.RABBIT_TYPE_SET, npc.getName(), type.name());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-04-19 05:54:05 +02:00
|
|
|
usage = "remove|rem (all|id|name| --owner [owner] | --eid [entity uuid] | --world [world])",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Remove a NPC",
|
|
|
|
modifiers = { "remove", "rem" },
|
|
|
|
min = 1,
|
|
|
|
max = 2)
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
2023-11-05 13:58:37 +01:00
|
|
|
public void remove(CommandContext args, CommandSender sender, NPC npc, @Flag("owner") String owner,
|
2022-09-07 21:01:39 +02:00
|
|
|
@Flag("eid") UUID eid, @Flag("world") String world, @Arg(value = 1, completions = "all") String action)
|
|
|
|
throws CommandException {
|
2022-09-06 20:11:07 +02:00
|
|
|
if (owner != null) {
|
2023-08-01 17:18:45 +02:00
|
|
|
UUID uuid = null;
|
|
|
|
try {
|
|
|
|
uuid = UUID.fromString(owner);
|
|
|
|
} catch (IllegalArgumentException ex) {
|
|
|
|
try {
|
|
|
|
uuid = Bukkit.getOfflinePlayer(owner).getUniqueId();
|
|
|
|
} catch (Exception e) {
|
|
|
|
}
|
|
|
|
}
|
2022-02-20 03:04:09 +01:00
|
|
|
for (NPC rem : Lists.newArrayList(CitizensAPI.getNPCRegistry())) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!rem.getOrAddTrait(Owner.class).isOwnedBy(sender)) {
|
2022-09-03 09:39:08 +02:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
|
|
|
if (uuid != null && rem.getOrAddTrait(Owner.class).isOwnedBy(uuid)
|
|
|
|
|| rem.getOrAddTrait(Owner.class).isOwnedBy(owner)) {
|
2022-02-20 03:04:09 +01:00
|
|
|
history.add(sender, new RemoveNPCHistoryItem(rem));
|
|
|
|
rem.destroy(sender);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.NPCS_REMOVED);
|
|
|
|
return;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (world != null) {
|
2022-04-19 05:54:05 +02:00
|
|
|
for (NPC rem : Lists.newArrayList(CitizensAPI.getNPCRegistry())) {
|
2022-04-19 12:13:40 +02:00
|
|
|
Location loc = rem.getStoredLocation();
|
2022-09-03 09:39:08 +02:00
|
|
|
if (loc != null && rem.getOrAddTrait(Owner.class).isOwnedBy(sender) && loc.getWorld() != null
|
|
|
|
&& (loc.getWorld().getUID().toString().equals(world)
|
|
|
|
|| loc.getWorld().getName().equalsIgnoreCase(world))) {
|
2022-04-19 05:54:05 +02:00
|
|
|
history.add(sender, new RemoveNPCHistoryItem(rem));
|
|
|
|
rem.destroy(sender);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.NPCS_REMOVED);
|
|
|
|
return;
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (eid != null) {
|
|
|
|
Entity entity = Bukkit.getServer().getEntity(eid);
|
2022-09-03 09:39:08 +02:00
|
|
|
if (entity != null && (npc = CitizensAPI.getNPCRegistry().getNPC(entity)) != null
|
|
|
|
&& npc.getOrAddTrait(Owner.class).isOwnedBy(sender)) {
|
2022-02-19 07:36:45 +01:00
|
|
|
history.add(sender, new RemoveNPCHistoryItem(npc));
|
2020-06-26 06:16:13 +02:00
|
|
|
npc.destroy(sender);
|
2022-07-09 19:17:26 +02:00
|
|
|
Messaging.sendTr(sender, Messages.NPC_REMOVED, npc.getName(), npc.getId());
|
2020-04-22 17:46:36 +02:00
|
|
|
} else {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.NPC_NOT_FOUND);
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
return;
|
2020-04-22 17:46:36 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.argsLength() == 2) {
|
2022-09-07 21:01:39 +02:00
|
|
|
if ("all".equalsIgnoreCase(action)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!sender.hasPermission("citizens.admin.remove.all") && !sender.hasPermission("citizens.admin"))
|
|
|
|
throw new NoPermissionsException();
|
2022-02-19 06:35:16 +01:00
|
|
|
for (NPC rem : CitizensAPI.getNPCRegistry()) {
|
2022-02-19 07:36:45 +01:00
|
|
|
history.add(sender, new RemoveNPCHistoryItem(rem));
|
2022-02-19 06:35:16 +01:00
|
|
|
}
|
2022-02-20 03:04:09 +01:00
|
|
|
CitizensAPI.getNPCRegistry().deregisterAll();
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, Messages.REMOVED_ALL_NPCS);
|
|
|
|
} else {
|
2023-03-14 13:55:33 +01:00
|
|
|
NPCCommandSelector.Callback callback = npc1 -> {
|
|
|
|
if (npc1 == null)
|
|
|
|
throw new CommandException(CommandMessages.MUST_HAVE_SELECTED);
|
|
|
|
if (!(sender instanceof ConsoleCommandSender) && !npc1.getOrAddTrait(Owner.class).isOwnedBy(sender))
|
|
|
|
throw new CommandException(CommandMessages.MUST_BE_OWNER);
|
|
|
|
if (!sender.hasPermission("citizens.npc.remove") && !sender.hasPermission("citizens.admin"))
|
|
|
|
throw new NoPermissionsException();
|
|
|
|
history.add(sender, new RemoveNPCHistoryItem(npc1));
|
|
|
|
npc1.destroy(sender);
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_REMOVED, npc1.getName(), npc1.getId());
|
2017-12-30 08:36:36 +01:00
|
|
|
};
|
2019-03-01 13:50:44 +01:00
|
|
|
NPCCommandSelector.startWithCallback(callback, CitizensAPI.getNPCRegistry(), sender, args,
|
|
|
|
args.getString(1));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
return;
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (npc == null)
|
2022-07-17 16:29:11 +02:00
|
|
|
throw new CommandException(CommandMessages.MUST_HAVE_SELECTED);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2020-09-14 11:57:58 +02:00
|
|
|
if (!(sender instanceof ConsoleCommandSender) && !npc.getOrAddTrait(Owner.class).isOwnedBy(sender))
|
2022-07-17 16:29:11 +02:00
|
|
|
throw new CommandException(CommandMessages.MUST_BE_OWNER);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!sender.hasPermission("citizens.npc.remove") && !sender.hasPermission("citizens.admin"))
|
|
|
|
throw new NoPermissionsException();
|
2022-09-06 20:11:07 +02:00
|
|
|
|
2022-02-19 07:36:45 +01:00
|
|
|
history.add(sender, new RemoveNPCHistoryItem(npc));
|
2020-06-26 06:16:13 +02:00
|
|
|
npc.destroy(sender);
|
2022-07-09 19:17:26 +02:00
|
|
|
Messaging.sendTr(sender, Messages.NPC_REMOVED, npc.getName(), npc.getId());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "rename [name]",
|
|
|
|
desc = "Rename a NPC",
|
|
|
|
modifiers = { "rename" },
|
|
|
|
min = 2,
|
|
|
|
permission = "citizens.npc.rename")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void rename(CommandContext args, CommandSender sender, NPC npc) {
|
|
|
|
String oldName = npc.getName();
|
2022-12-18 06:50:19 +01:00
|
|
|
String newName = args.getJoinedStrings(1);
|
2020-09-14 11:57:58 +02:00
|
|
|
int nameLength = SpigotUtil.getMaxNameLength(npc.getOrAddTrait(MobType.class).getType());
|
2022-12-25 17:20:21 +01:00
|
|
|
if (Placeholders.replace(Messaging.parseComponents(newName), sender, npc).length() > nameLength) {
|
2020-07-06 15:27:48 +02:00
|
|
|
Messaging.sendErrorTr(sender, Messages.NPC_NAME_TOO_LONG, nameLength);
|
2017-12-30 08:36:36 +01:00
|
|
|
newName = newName.substring(0, nameLength);
|
|
|
|
}
|
|
|
|
npc.setName(newName);
|
|
|
|
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_RENAMED, oldName, newName);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-04-29 20:39:26 +02:00
|
|
|
usage = "respawn [delay]",
|
|
|
|
desc = "Sets an NPC's respawn delay",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "respawn" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.respawn")
|
2023-03-12 15:29:41 +01:00
|
|
|
public void respawn(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Duration delay) {
|
|
|
|
if (delay != null) {
|
|
|
|
npc.data().setPersistent(NPC.Metadata.RESPAWN_DELAY, Util.toTicks(delay));
|
2023-04-25 17:56:50 +02:00
|
|
|
Messaging.sendTr(sender, Messages.RESPAWN_DELAY_SET, Util.toTicks(delay));
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
Messaging.sendTr(sender, Messages.RESPAWN_DELAY_DESCRIBE, npc.data().get(NPC.Metadata.RESPAWN_DELAY, -1));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-28 16:10:50 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-11-15 15:39:09 +01:00
|
|
|
usage = "rotate (--towards [x,y,z]) (--body [yaw]) (--head [yaw]) (--pitch [pitch]) (-s(mooth))",
|
2022-11-28 16:10:50 +01:00
|
|
|
desc = "Rotate NPC",
|
|
|
|
flags = "s",
|
|
|
|
modifiers = { "rotate" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.rotate")
|
|
|
|
public void rotate(CommandContext args, CommandSender sender, NPC npc, @Flag("body") Float yaw,
|
2023-11-15 15:39:09 +01:00
|
|
|
@Flag("head") Float head, @Flag("pitch") Float pitch, @Flag("towards") Location towards) {
|
2022-11-28 16:10:50 +01:00
|
|
|
if (args.hasFlag('s')) {
|
|
|
|
if (pitch == null) {
|
|
|
|
pitch = npc.getStoredLocation().getPitch();
|
|
|
|
}
|
|
|
|
if (yaw == null) {
|
|
|
|
if (head != null) {
|
|
|
|
yaw = head;
|
|
|
|
} else {
|
|
|
|
yaw = NMS.getHeadYaw(npc.getEntity());
|
|
|
|
}
|
|
|
|
}
|
2022-12-06 16:50:11 +01:00
|
|
|
npc.getOrAddTrait(RotationTrait.class).getPhysicalSession().rotateToHave(yaw, pitch);
|
2022-11-28 16:10:50 +01:00
|
|
|
return;
|
|
|
|
}
|
2023-11-15 15:39:09 +01:00
|
|
|
if (towards != null) {
|
|
|
|
npc.getOrAddTrait(RotationTrait.class).getPhysicalSession().rotateToFace(towards);
|
|
|
|
return;
|
|
|
|
}
|
2022-11-28 16:10:50 +01:00
|
|
|
if (yaw != null) {
|
|
|
|
NMS.setBodyYaw(npc.getEntity(), yaw);
|
2022-12-24 14:43:08 +01:00
|
|
|
if (npc.getEntity().getType() == EntityType.PLAYER) {
|
2023-05-01 18:50:50 +02:00
|
|
|
NMS.sendPositionUpdate(npc.getEntity(), true, yaw, npc.getStoredLocation().getPitch(), null);
|
2023-05-03 19:51:48 +02:00
|
|
|
PlayerAnimation.ARM_SWING.play((Player) npc.getEntity());
|
2022-12-24 14:43:08 +01:00
|
|
|
}
|
2022-11-28 16:10:50 +01:00
|
|
|
}
|
|
|
|
if (pitch != null) {
|
|
|
|
NMS.setPitch(npc.getEntity(), pitch);
|
|
|
|
}
|
|
|
|
if (head != null) {
|
|
|
|
NMS.setHeadYaw(npc.getEntity(), head);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-12-27 12:57:48 +01:00
|
|
|
usage = "select|sel [id|name] (--range range) (--registry [name])",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Select a NPC with the given ID or name",
|
|
|
|
modifiers = { "select", "sel" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.select")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
2023-11-05 13:58:37 +01:00
|
|
|
public void select(CommandContext args, CommandSender sender, NPC npc,
|
2022-09-06 20:11:07 +02:00
|
|
|
@Flag(value = "range", defValue = "10") double range, @Flag("registry") String registryName)
|
|
|
|
throws CommandException {
|
2023-03-14 13:55:33 +01:00
|
|
|
NPCCommandSelector.Callback callback = toSelect -> {
|
|
|
|
if (toSelect == null)
|
|
|
|
throw new CommandException(Messages.NPC_NOT_FOUND);
|
|
|
|
if (npc != null && toSelect.getId() == npc.getId())
|
|
|
|
throw new CommandException(Messages.NPC_ALREADY_SELECTED);
|
|
|
|
selector.select(sender, toSelect);
|
|
|
|
Messaging.sendWithNPC(sender, Setting.SELECTION_MESSAGE.asString(), toSelect);
|
2017-12-30 08:36:36 +01:00
|
|
|
};
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2022-09-06 20:11:07 +02:00
|
|
|
NPCRegistry registry = registryName != null ? CitizensAPI.getNamedNPCRegistry(registryName)
|
2020-11-17 02:12:41 +01:00
|
|
|
: CitizensAPI.getNPCRegistry();
|
2022-07-24 18:23:44 +02:00
|
|
|
if (registry == null)
|
|
|
|
throw new CommandException(Messages.UNKNOWN_NPC_REGISTRY, args.getFlag("registry"));
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.argsLength() <= 1) {
|
2023-03-14 13:55:33 +01:00
|
|
|
if (args.getSenderLocation() == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new ServerCommandException();
|
2023-11-05 13:58:37 +01:00
|
|
|
Location location = args.getSenderLocation();
|
2023-03-14 13:55:33 +01:00
|
|
|
List<NPC> search = location.getWorld().getNearbyEntities(location, range, range, range).stream()
|
|
|
|
.map(e -> registry.getNPC(e)).filter(e -> e != null).collect(Collectors.toList());
|
|
|
|
Collections.sort(search, (o1, o2) -> Double.compare(o1.getEntity().getLocation().distanceSquared(location),
|
|
|
|
o2.getEntity().getLocation().distanceSquared(location)));
|
|
|
|
for (NPC test : search) {
|
2021-02-02 15:33:06 +01:00
|
|
|
if (test.hasTrait(ClickRedirectTrait.class)) {
|
|
|
|
test = test.getTraitNullable(ClickRedirectTrait.class).getRedirectNPC();
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
callback.run(test);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
2020-11-17 02:12:41 +01:00
|
|
|
NPCCommandSelector.startWithCallback(callback, registry, sender, args, args.getString(1));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-18 11:23:55 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "setequipment [slot] [item]",
|
|
|
|
desc = "Sets equipment via commands",
|
|
|
|
modifiers = { "setequipment" },
|
|
|
|
min = 2,
|
|
|
|
max = 3,
|
|
|
|
permission = "citizens.npc.setequipment")
|
|
|
|
public void setequipment(CommandContext args, CommandSender sender, NPC npc, @Arg(1) EquipmentSlot slot,
|
|
|
|
@Arg(2) ItemStack item) throws CommandException {
|
|
|
|
if (slot == null)
|
|
|
|
throw new CommandUsageException();
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2023-06-18 11:23:55 +02:00
|
|
|
if (item == null && args.argsLength() == 3 && args.getString(2).equalsIgnoreCase("hand")) {
|
|
|
|
if (!(sender instanceof Player))
|
|
|
|
throw new ServerCommandException();
|
|
|
|
item = ((Player) sender).getItemInHand().clone();
|
|
|
|
}
|
|
|
|
npc.getOrAddTrait(Equipment.class).set(slot, item);
|
|
|
|
Messaging.sendTr(sender, Messages.EQUIPMENT_SET, slot, item);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "sheep (--color [color]) (--sheared [sheared])",
|
|
|
|
desc = "Sets sheep modifiers",
|
|
|
|
modifiers = { "sheep" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.sheep")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.SHEEP })
|
2022-09-06 20:11:07 +02:00
|
|
|
public void sheep(CommandContext args, CommandSender sender, NPC npc, @Flag("color") DyeColor color,
|
|
|
|
@Flag("sheared") Boolean sheared) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
SheepTrait trait = npc.getOrAddTrait(SheepTrait.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
boolean hasArg = false;
|
2022-09-06 20:11:07 +02:00
|
|
|
if (sheared != null) {
|
|
|
|
trait.setSheared(sheared);
|
2017-12-30 08:36:36 +01:00
|
|
|
hasArg = true;
|
|
|
|
}
|
|
|
|
if (args.hasValueFlag("color")) {
|
|
|
|
if (color != null) {
|
|
|
|
trait.setColor(color);
|
|
|
|
Messaging.sendTr(sender, Messages.SHEEP_COLOR_SET, color.toString().toLowerCase());
|
|
|
|
} else {
|
|
|
|
Messaging.sendErrorTr(sender, Messages.INVALID_SHEEP_COLOR, Util.listValuesPretty(DyeColor.values()));
|
|
|
|
}
|
|
|
|
hasArg = true;
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!hasArg)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new CommandException();
|
|
|
|
}
|
|
|
|
|
2021-07-14 15:23:55 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-11-29 23:13:55 +01:00
|
|
|
usage = "shop (edit|show|delete) (name)",
|
2021-07-14 15:23:55 +02:00
|
|
|
desc = "NPC shop edit/show",
|
|
|
|
modifiers = { "shop" },
|
|
|
|
min = 1,
|
|
|
|
max = 3,
|
|
|
|
permission = "citizens.npc.shop")
|
2022-12-18 18:44:16 +01:00
|
|
|
@Requirements(selected = false, ownership = true)
|
2022-09-07 21:01:39 +02:00
|
|
|
public void shop(CommandContext args, Player sender, NPC npc,
|
2022-11-29 23:13:55 +01:00
|
|
|
@Arg(value = 1, completions = { "edit", "show", "delete" }) String action) throws CommandException {
|
2022-12-18 18:44:16 +01:00
|
|
|
if (args.argsLength() == 1) {
|
|
|
|
if (npc != null) {
|
|
|
|
npc.getOrAddTrait(ShopTrait.class).getDefaultShop().display(sender);
|
2022-02-19 13:27:41 +01:00
|
|
|
}
|
2022-12-18 18:44:16 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
NPCShop shop = npc != null ? npc.getOrAddTrait(ShopTrait.class).getDefaultShop() : null;
|
|
|
|
if (args.argsLength() == 3) {
|
|
|
|
shop = shops.getShop(args.getString(2).toLowerCase());
|
|
|
|
}
|
2023-01-01 08:26:35 +01:00
|
|
|
if (shop == null)
|
|
|
|
throw new CommandUsageException();
|
|
|
|
|
2022-12-18 18:44:16 +01:00
|
|
|
if (action.equalsIgnoreCase("delete")) {
|
2023-01-01 08:26:35 +01:00
|
|
|
if (args.argsLength() != 3)
|
2021-07-14 15:23:55 +02:00
|
|
|
throw new CommandUsageException();
|
2023-01-01 08:26:35 +01:00
|
|
|
if (!shop.canEdit(npc, sender))
|
2022-12-29 16:26:02 +01:00
|
|
|
throw new NoPermissionsException();
|
|
|
|
shops.deleteShop(shop);
|
2023-01-01 08:26:35 +01:00
|
|
|
} else if (action.equalsIgnoreCase("edit")) {
|
|
|
|
if (!shop.canEdit(npc, sender))
|
2022-12-18 18:44:16 +01:00
|
|
|
throw new NoPermissionsException();
|
|
|
|
shop.displayEditor(npc == null ? null : npc.getOrAddTrait(ShopTrait.class), sender);
|
|
|
|
} else if (action.equalsIgnoreCase("show")) {
|
2022-02-19 13:27:41 +01:00
|
|
|
shop.display(sender);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2022-12-18 18:44:16 +01:00
|
|
|
throw new CommandUsageException();
|
2021-07-14 15:23:55 +02:00
|
|
|
}
|
|
|
|
|
2023-06-08 16:37:50 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "sitting (--explicit [true|false]) (--at [at])",
|
|
|
|
desc = "Sets the NPC sitting",
|
|
|
|
modifiers = { "sitting" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.sitting")
|
|
|
|
@Requirements(selected = true, ownership = true)
|
|
|
|
public void sitting(CommandContext args, CommandSender sender, NPC npc, @Flag("explicit") Boolean explicit,
|
|
|
|
@Flag("at") Location at) {
|
|
|
|
SitTrait trait = npc.getOrAddTrait(SitTrait.class);
|
|
|
|
boolean toSit = explicit != null ? explicit : !trait.isSitting();
|
|
|
|
if (!toSit) {
|
|
|
|
trait.setSitting(null);
|
|
|
|
Messaging.sendTr(sender, Messages.SITTING_UNSET, npc.getName());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (at == null) {
|
|
|
|
at = npc.getStoredLocation();
|
|
|
|
}
|
|
|
|
trait.setSitting(at);
|
2023-06-11 10:51:28 +02:00
|
|
|
Messaging.sendTr(sender, Messages.SITTING_SET, npc.getName(), Util.prettyPrintLocation(at));
|
2023-06-08 16:37:50 +02:00
|
|
|
}
|
|
|
|
|
2023-08-27 19:49:14 +02:00
|
|
|
@Command(
|
2020-02-14 15:48:40 +01:00
|
|
|
aliases = { "npc" },
|
2023-11-04 19:03:57 +01:00
|
|
|
usage = "skin (-e(xport) -c(lear) -l(atest) -s(kull)) [name] (or --url [url] --file [file] (-s(lim)) or -t [uuid/name] [data] [signature])",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets an NPC's skin name. Use -l to set the skin to always update to the latest",
|
|
|
|
modifiers = { "skin" },
|
|
|
|
min = 1,
|
|
|
|
max = 4,
|
2023-08-13 19:16:00 +02:00
|
|
|
flags = "ectls",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.skin")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(types = EntityType.PLAYER, selected = true, ownership = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void skin(CommandContext args, CommandSender sender, NPC npc, @Flag("url") String url,
|
2023-03-28 19:28:08 +02:00
|
|
|
@Flag("file") String file) throws CommandException {
|
2017-12-30 08:36:36 +01:00
|
|
|
String skinName = npc.getName();
|
2023-11-05 13:58:37 +01:00
|
|
|
SkinTrait trait = npc.getOrAddTrait(SkinTrait.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('c')) {
|
2020-04-18 20:07:03 +02:00
|
|
|
trait.clearTexture();
|
2023-06-25 15:58:09 +02:00
|
|
|
Messaging.sendTr(sender, Messages.SKIN_CLEARED);
|
2023-08-13 19:16:00 +02:00
|
|
|
return;
|
|
|
|
} else if (args.hasFlag('e')) {
|
|
|
|
if (trait.getTexture() == null)
|
|
|
|
throw new CommandException(Messages.SKIN_REQUIRED);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2023-08-13 19:16:00 +02:00
|
|
|
File skinsFolder = new File(CitizensAPI.getDataFolder(), "skins");
|
|
|
|
File skin = file == null ? new File(skinsFolder, npc.getUniqueId().toString() + ".png")
|
|
|
|
: new File(skinsFolder, file);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2023-08-13 19:16:00 +02:00
|
|
|
if (!skin.getParentFile().equals(skinsFolder) || !skin.getName().endsWith(".png"))
|
|
|
|
throw new CommandException(Messages.INVALID_SKIN_FILE, file);
|
|
|
|
|
|
|
|
try {
|
|
|
|
JSONObject data = (JSONObject) new JSONParser()
|
|
|
|
.parse(new String(BaseEncoding.base64().decode(trait.getTexture())));
|
|
|
|
JSONObject textures = (JSONObject) data.get("textures");
|
|
|
|
JSONObject skinObj = (JSONObject) textures.get("SKIN");
|
|
|
|
URL textureUrl = new URL(skinObj.get("url").toString().replace("\\", ""));
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2023-08-13 19:16:00 +02:00
|
|
|
if (!textureUrl.getHost().equals("textures.minecraft.net"))
|
|
|
|
throw new CommandException(Messages.ERROR_SETTING_SKIN_URL, "Mojang");
|
|
|
|
|
|
|
|
try (ReadableByteChannel in = Channels.newChannel(textureUrl.openStream());
|
|
|
|
FileOutputStream out = new FileOutputStream(skin)) {
|
|
|
|
out.getChannel().transferFrom(in, 0, 10000);
|
|
|
|
}
|
|
|
|
Messaging.send(sender, Messages.SKIN_EXPORTED, skin.getName());
|
|
|
|
} catch (Exception e) {
|
|
|
|
throw new CommandException("Couldn't parse texture: " + e.getMessage());
|
|
|
|
}
|
2023-06-25 15:58:09 +02:00
|
|
|
return;
|
2023-03-28 19:28:08 +02:00
|
|
|
} else if (url != null || file != null) {
|
2023-10-01 11:27:38 +02:00
|
|
|
Messaging.sendTr(sender, Messages.FETCHING_SKIN, url == null ? file : url);
|
2023-03-28 19:28:08 +02:00
|
|
|
Bukkit.getScheduler().runTaskAsynchronously(CitizensAPI.getPlugin(), () -> {
|
|
|
|
try {
|
|
|
|
JSONObject data = null;
|
|
|
|
if (file != null) {
|
2023-03-29 12:32:47 +02:00
|
|
|
File skinsFolder = new File(CitizensAPI.getDataFolder(), "skins");
|
2023-10-01 11:27:38 +02:00
|
|
|
File skin = new File(skinsFolder, Placeholders.replace(file, sender, npc));
|
2023-03-29 12:32:47 +02:00
|
|
|
if (!skin.exists() || !skin.isFile() || skin.isHidden()
|
|
|
|
|| !skin.getParentFile().equals(skinsFolder)) {
|
2023-03-28 19:28:08 +02:00
|
|
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(),
|
|
|
|
() -> Messaging.sendErrorTr(sender, Messages.INVALID_SKIN_FILE, file));
|
|
|
|
return;
|
2020-03-20 10:29:23 +01:00
|
|
|
}
|
2023-03-29 12:32:47 +02:00
|
|
|
data = MojangSkinGenerator.generateFromPNG(Files.readAllBytes(skin.toPath()),
|
|
|
|
args.hasFlag('s'));
|
2023-03-28 19:28:08 +02:00
|
|
|
} else {
|
2023-10-01 11:27:38 +02:00
|
|
|
data = MojangSkinGenerator.generateFromURL(Placeholders.replace(url, sender, npc),
|
|
|
|
args.hasFlag('s'));
|
2023-03-28 19:28:08 +02:00
|
|
|
}
|
|
|
|
String uuid = (String) data.get("uuid");
|
|
|
|
JSONObject texture = (JSONObject) data.get("texture");
|
|
|
|
String textureEncoded = (String) texture.get("value");
|
|
|
|
String signature = (String) texture.get("signature");
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2023-03-28 19:28:08 +02:00
|
|
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
try {
|
|
|
|
trait.setSkinPersistent(uuid, signature, textureEncoded);
|
2023-03-29 12:32:47 +02:00
|
|
|
Messaging.sendTr(sender, Messages.SKIN_URL_SET, npc.getName(), url == null ? file : url);
|
2023-03-28 19:28:08 +02:00
|
|
|
} catch (IllegalArgumentException e) {
|
2023-03-29 12:32:47 +02:00
|
|
|
Messaging.sendErrorTr(sender, Messages.ERROR_SETTING_SKIN_URL, url == null ? file : url);
|
2020-03-20 10:29:23 +01:00
|
|
|
}
|
2023-03-28 19:28:08 +02:00
|
|
|
});
|
|
|
|
} catch (Throwable t) {
|
|
|
|
if (Messaging.isDebugging()) {
|
|
|
|
t.printStackTrace();
|
2020-03-20 10:29:23 +01:00
|
|
|
}
|
2023-03-29 12:32:47 +02:00
|
|
|
Bukkit.getScheduler().runTask(CitizensAPI.getPlugin(), () -> Messaging.sendErrorTr(sender,
|
|
|
|
Messages.ERROR_SETTING_SKIN_URL, url == null ? file : url));
|
2020-03-20 10:29:23 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
2018-04-17 09:50:12 +02:00
|
|
|
} else if (args.hasFlag('t')) {
|
2018-04-18 13:29:20 +02:00
|
|
|
if (args.argsLength() != 4)
|
2018-04-17 09:50:12 +02:00
|
|
|
throw new CommandException(Messages.SKIN_REQUIRED);
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2020-04-18 20:13:00 +02:00
|
|
|
trait.setSkinPersistent(args.getString(1), args.getString(3), args.getString(2));
|
2018-04-17 09:50:12 +02:00
|
|
|
Messaging.sendTr(sender, Messages.SKIN_SET, npc.getName(), args.getString(1));
|
|
|
|
return;
|
2023-11-04 05:47:07 +01:00
|
|
|
} else if (args.hasFlag('s') && npc.getEntity() instanceof Player) {
|
|
|
|
ItemStack is = new ItemStack(Material.PLAYER_HEAD);
|
|
|
|
SkullMeta sm = (SkullMeta) is.getItemMeta();
|
|
|
|
NMS.setProfile(sm, NMS.getProfile((Player) npc.getEntity()));
|
|
|
|
is.setItemMeta(sm);
|
|
|
|
if (sender instanceof Player && ((Player) sender).getInventory().addItem(is).isEmpty()) {
|
|
|
|
} else if (args.getSenderLocation() != null) {
|
|
|
|
args.getSenderLocation().getWorld().dropItem(args.getSenderLocation(), is);
|
2023-11-05 13:58:37 +01:00
|
|
|
} else
|
2023-11-04 05:47:07 +01:00
|
|
|
throw new ServerCommandException();
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
|
|
|
if (args.argsLength() != 2)
|
2018-03-09 09:41:01 +01:00
|
|
|
throw new CommandException(Messages.SKIN_REQUIRED);
|
2018-03-09 15:15:26 +01:00
|
|
|
if (args.hasFlag('l')) {
|
2020-04-18 20:07:03 +02:00
|
|
|
trait.setShouldUpdateSkins(true);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
skinName = args.getString(1);
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.SKIN_SET, npc.getName(), skinName);
|
2020-04-18 20:09:46 +02:00
|
|
|
trait.setSkinName(skinName, true);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "skinlayers (--cape [true|false]) (--hat [true|false]) (--jacket [true|false]) (--sleeves [true|false]) (--pants [true|false])",
|
|
|
|
desc = "Sets an NPC's skin layers visibility.",
|
|
|
|
modifiers = { "skinlayers" },
|
|
|
|
min = 1,
|
|
|
|
max = 5,
|
|
|
|
permission = "citizens.npc.skinlayers")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(types = EntityType.PLAYER, selected = true, ownership = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void skinLayers(CommandContext args, CommandSender sender, NPC npc, @Flag("cape") Boolean cape,
|
|
|
|
@Flag("hat") Boolean hat, @Flag("jacket") Boolean jacket, @Flag("sleeves") Boolean sleeves,
|
|
|
|
@Flag("pants") Boolean pants) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
SkinLayers trait = npc.getOrAddTrait(SkinLayers.class);
|
2022-09-06 20:11:07 +02:00
|
|
|
if (cape != null) {
|
|
|
|
trait.setVisible(Layer.CAPE, cape);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (hat != null) {
|
|
|
|
trait.setVisible(Layer.HAT, hat);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (jacket != null) {
|
|
|
|
trait.setVisible(Layer.JACKET, jacket);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (sleeves != null) {
|
|
|
|
trait.setVisible(Layer.LEFT_SLEEVE, sleeves);
|
|
|
|
trait.setVisible(Layer.RIGHT_SLEEVE, sleeves);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (pants != null) {
|
|
|
|
trait.setVisible(Layer.LEFT_PANTS, pants);
|
|
|
|
trait.setVisible(Layer.RIGHT_PANTS, pants);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.SKIN_LAYERS_SET, npc.getName(), trait.isVisible(Layer.CAPE),
|
|
|
|
trait.isVisible(Layer.HAT), trait.isVisible(Layer.JACKET),
|
|
|
|
trait.isVisible(Layer.LEFT_SLEEVE) || trait.isVisible(Layer.RIGHT_SLEEVE),
|
|
|
|
trait.isVisible(Layer.LEFT_PANTS) || trait.isVisible(Layer.RIGHT_PANTS));
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "size [size]",
|
|
|
|
desc = "Sets the NPC's size",
|
|
|
|
modifiers = { "size" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.size")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.MAGMA_CUBE, EntityType.SLIME })
|
|
|
|
public void slimeSize(CommandContext args, CommandSender sender, NPC npc) {
|
2020-09-14 11:57:58 +02:00
|
|
|
SlimeSize trait = npc.getOrAddTrait(SlimeSize.class);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.argsLength() <= 1) {
|
|
|
|
trait.describe(sender);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int size = Math.max(-2, args.getInteger(1));
|
|
|
|
trait.setSize(size);
|
|
|
|
Messaging.sendTr(sender, Messages.SIZE_SET, npc.getName(), size);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2020-05-08 07:36:58 +02:00
|
|
|
usage = "sound (--death [death sound|d]) (--ambient [ambient sound|d]) (--hurt [hurt sound|d]) (-n(one)/-s(ilent)) (-d(efault))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets an NPC's played sounds",
|
|
|
|
modifiers = { "sound" },
|
|
|
|
flags = "dns",
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.sound")
|
2022-06-24 06:43:23 +02:00
|
|
|
@Requirements(selected = true, ownership = true, livingEntity = true)
|
2023-06-19 14:55:16 +02:00
|
|
|
public void sound(CommandContext args, CommandSender sender, NPC npc, @Flag("death") Sound death,
|
|
|
|
@Flag("ambient") Sound ambient, @Flag("hurt") Sound hurt) throws CommandException {
|
2023-01-01 08:26:35 +01:00
|
|
|
String ambientSound = npc.data().get(NPC.Metadata.AMBIENT_SOUND);
|
|
|
|
String deathSound = npc.data().get(NPC.Metadata.DEATH_SOUND);
|
|
|
|
String hurtSound = npc.data().get(NPC.Metadata.HURT_SOUND);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.getValueFlags().size() == 0 && args.getFlags().size() == 0) {
|
|
|
|
Messaging.sendTr(sender, Messages.SOUND_INFO, npc.getName(), ambientSound, hurtSound, deathSound);
|
|
|
|
return;
|
|
|
|
}
|
2020-05-08 07:36:58 +02:00
|
|
|
if (args.hasFlag('n')) {
|
2017-12-30 08:36:36 +01:00
|
|
|
ambientSound = deathSound = hurtSound = "";
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.SILENT, true);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-05-08 07:36:58 +02:00
|
|
|
if (args.hasFlag('s')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.SILENT, !npc.data().get(NPC.Metadata.SILENT, false));
|
2020-05-08 07:36:58 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('d')) {
|
|
|
|
ambientSound = deathSound = hurtSound = null;
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.SILENT, false);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2022-09-06 20:11:07 +02:00
|
|
|
if (death != null) {
|
2023-06-19 14:55:16 +02:00
|
|
|
deathSound = NMS.getSoundPath(death);
|
|
|
|
} else if (args.hasValueFlag("death")) {
|
|
|
|
deathSound = args.getFlag("death").equals("d") ? null : args.getFlag("death");
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (ambient != null) {
|
2023-06-19 14:55:16 +02:00
|
|
|
ambientSound = NMS.getSoundPath(ambient);
|
|
|
|
} else if (args.hasValueFlag("ambient")) {
|
|
|
|
ambientSound = args.getFlag("ambient").equals("d") ? null : args.getFlag("ambient");
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (hurt != null) {
|
2023-06-19 14:55:16 +02:00
|
|
|
hurtSound = NMS.getSoundPath(hurt);
|
|
|
|
} else if (args.hasValueFlag("hurt")) {
|
|
|
|
hurtSound = args.getFlag("hurt").equals("d") ? null : args.getFlag("hurt");
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (deathSound == null) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().remove(NPC.Metadata.DEATH_SOUND);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.DEATH_SOUND, deathSound);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (hurtSound == null) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().remove(NPC.Metadata.HURT_SOUND);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.HURT_SOUND, hurtSound);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (ambientSound == null) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().remove(NPC.Metadata.AMBIENT_SOUND);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.AMBIENT_SOUND, ambientSound);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
if (ambientSound != null && ambientSound.isEmpty()) {
|
|
|
|
ambientSound = "none";
|
|
|
|
}
|
|
|
|
if (hurtSound != null && hurtSound.isEmpty()) {
|
|
|
|
hurtSound = "none";
|
|
|
|
}
|
|
|
|
if (deathSound != null && deathSound.isEmpty()) {
|
|
|
|
deathSound = "none";
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!Strings.isNullOrEmpty(ambientSound) && !ambientSound.equals("none")
|
|
|
|
|| !Strings.isNullOrEmpty(deathSound) && !deathSound.equals("none")
|
|
|
|
|| !Strings.isNullOrEmpty(hurtSound) && !hurtSound.equals("none")) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.SILENT, false);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.SOUND_SET, npc.getName(), ambientSound, hurtSound, deathSound);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "spawn (id|name) -l(oad chunks)",
|
|
|
|
desc = "Spawn an existing NPC",
|
|
|
|
modifiers = { "spawn" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
flags = "l",
|
|
|
|
permission = "citizens.npc.spawn")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(ownership = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void spawn(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2023-03-14 13:55:33 +01:00
|
|
|
NPCCommandSelector.Callback callback = respawn -> {
|
|
|
|
if (respawn == null) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (args.argsLength() > 1)
|
2023-03-14 13:55:33 +01:00
|
|
|
throw new CommandException(Messages.NO_NPC_WITH_ID_FOUND, args.getString(1));
|
2023-11-05 13:58:37 +01:00
|
|
|
else
|
2023-03-14 13:55:33 +01:00
|
|
|
throw new CommandException(CommandMessages.MUST_HAVE_SELECTED);
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
if (respawn.isSpawned())
|
2023-03-14 13:55:33 +01:00
|
|
|
throw new CommandException(Messages.NPC_ALREADY_SPAWNED, respawn.getName());
|
|
|
|
Location location = respawn.getOrAddTrait(CurrentLocation.class).getLocation();
|
|
|
|
if (location == null || args.hasValueFlag("location")) {
|
|
|
|
if (args.getSenderLocation() == null)
|
|
|
|
throw new CommandException(Messages.NO_STORED_SPAWN_LOCATION);
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2023-03-14 13:55:33 +01:00
|
|
|
location = args.getSenderLocation();
|
|
|
|
}
|
|
|
|
if (args.hasFlag('l') && !Util.isLoaded(location)) {
|
|
|
|
location.getChunk().load();
|
|
|
|
}
|
|
|
|
if (respawn.spawn(location, SpawnReason.COMMAND)) {
|
|
|
|
selector.select(sender, respawn);
|
|
|
|
Messaging.sendTr(sender, Messages.NPC_SPAWNED, respawn.getName());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
};
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.argsLength() > 1) {
|
2019-03-01 13:50:44 +01:00
|
|
|
NPCCommandSelector.startWithCallback(callback, CitizensAPI.getNPCRegistry(), sender, args,
|
|
|
|
args.getString(1));
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
|
|
|
callback.run(npc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-09-03 17:41:38 +02:00
|
|
|
usage = "speak [message] --bubble [duration] --target [npcid|player name] --range (range to look for entities to speak to in blocks)",
|
2022-06-25 10:47:13 +02:00
|
|
|
desc = "Says a message from the NPC",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "speak" },
|
|
|
|
min = 2,
|
|
|
|
permission = "citizens.npc.speak")
|
2023-09-03 17:41:38 +02:00
|
|
|
public void speak(CommandContext args, CommandSender sender, NPC npc, @Flag("bubble") Duration bubbleDuration,
|
|
|
|
@Flag("type") String type, @Flag("target") String target, @Flag("range") Float range)
|
|
|
|
throws CommandException {
|
2022-12-18 06:50:19 +01:00
|
|
|
String message = args.getJoinedStrings(1);
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
SpeechContext context = new SpeechContext(message);
|
|
|
|
|
2023-09-03 17:41:38 +02:00
|
|
|
Player playerRecipient = null;
|
2022-09-06 20:11:07 +02:00
|
|
|
if (target != null) {
|
|
|
|
if (target.matches("\\d+")) {
|
2023-11-05 13:58:37 +01:00
|
|
|
NPC targetNPC = CitizensAPI.getNPCRegistry().getById(Integer.parseInt(args.getFlag("target")));
|
|
|
|
if (targetNPC != null) {
|
2022-09-06 20:11:07 +02:00
|
|
|
context.addRecipient(targetNPC.getEntity());
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2022-09-06 20:11:07 +02:00
|
|
|
Player player = Bukkit.getPlayerExact(target);
|
2017-12-30 08:36:36 +01:00
|
|
|
if (player != null) {
|
2023-01-01 08:26:35 +01:00
|
|
|
context.addRecipient(player);
|
2023-09-03 17:41:38 +02:00
|
|
|
playerRecipient = player;
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-03 17:41:38 +02:00
|
|
|
if (bubbleDuration != null) {
|
|
|
|
HologramTrait trait = npc.getOrAddTrait(HologramTrait.class);
|
|
|
|
trait.addTemporaryLine(Placeholders.replace(message, playerRecipient, npc), Util.toTicks(bubbleDuration));
|
|
|
|
return;
|
|
|
|
}
|
2022-10-15 10:59:09 +02:00
|
|
|
if (range != null) {
|
2023-03-14 13:55:33 +01:00
|
|
|
npc.getEntity().getNearbyEntities(range, range, range).forEach(e -> {
|
2022-10-15 10:59:09 +02:00
|
|
|
if (!CitizensAPI.getNPCRegistry().isNPC(e)) {
|
|
|
|
context.addRecipient(e);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2023-04-20 17:42:48 +02:00
|
|
|
npc.getDefaultSpeechController().speak(context);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "speed [speed]",
|
|
|
|
desc = "Sets the movement speed of an NPC as a percentage",
|
|
|
|
modifiers = { "speed" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.speed")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void speed(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
float newSpeed = (float) Math.abs(args.getDouble(1));
|
|
|
|
npc.getNavigator().getDefaultParameters().speedModifier(newSpeed);
|
|
|
|
|
|
|
|
Messaging.sendTr(sender, Messages.SPEED_MODIFIER_SET, newSpeed);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "swim (--set [true|false])",
|
|
|
|
desc = "Sets an NPC to swim or not",
|
|
|
|
modifiers = { "swim" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.swim")
|
2022-09-06 20:11:07 +02:00
|
|
|
public void swim(CommandContext args, CommandSender sender, NPC npc, @Flag("set") Boolean set)
|
|
|
|
throws CommandException {
|
|
|
|
boolean swim = set != null ? set : !npc.data().get(NPC.Metadata.SWIMMING, true);
|
2022-02-19 09:36:31 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.SWIMMING, swim);
|
2017-12-30 08:36:36 +01:00
|
|
|
Messaging.sendTr(sender, swim ? Messages.SWIMMING_SET : Messages.SWIMMING_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2021-12-27 16:59:21 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-06-11 09:17:17 +02:00
|
|
|
usage = "target [name|UUID] (-a[ggressive]) (-c[ancel])",
|
2021-12-27 16:59:21 +01:00
|
|
|
desc = "Target a given entity",
|
|
|
|
modifiers = { "target" },
|
2022-06-11 09:17:17 +02:00
|
|
|
flags = "ac",
|
2021-12-27 16:59:21 +01:00
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.target")
|
|
|
|
public void target(CommandContext args, Player sender, NPC npc) {
|
2022-06-11 09:17:17 +02:00
|
|
|
if (args.hasFlag('c')) {
|
|
|
|
npc.getNavigator().cancelNavigation();
|
|
|
|
return;
|
|
|
|
}
|
2021-12-27 16:59:21 +01:00
|
|
|
Entity toTarget = args.argsLength() < 2 ? sender : Bukkit.getPlayer(args.getString(1));
|
|
|
|
if (toTarget == null) {
|
|
|
|
toTarget = Bukkit.getEntity(UUID.fromString(args.getString(1)));
|
|
|
|
}
|
|
|
|
if (toTarget != null) {
|
|
|
|
npc.getNavigator().setTarget(toTarget, args.hasFlag('a'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-07-05 13:13:31 +02:00
|
|
|
usage = "targetable (-t(emporary))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Toggles an NPC's targetability",
|
|
|
|
modifiers = { "targetable" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2022-07-05 13:13:31 +02:00
|
|
|
flags = "t",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.targetable")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void targetable(CommandContext args, CommandSender sender, NPC npc) {
|
2023-05-14 16:54:45 +02:00
|
|
|
boolean targetable = !npc.data().get(NPC.Metadata.TARGETABLE, !npc.isProtected());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('t')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().set(NPC.Metadata.TARGETABLE, targetable);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.TARGETABLE, targetable);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, targetable ? Messages.TARGETABLE_SET : Messages.TARGETABLE_UNSET, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-07-26 17:50:28 +02:00
|
|
|
usage = "tp (-e(xact))",
|
|
|
|
desc = "Teleport in front of an NPC",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "tp", "teleport" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
2022-07-26 17:50:28 +02:00
|
|
|
flags = "e",
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.tp")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void tp(CommandContext args, Player player, NPC npc) {
|
2020-09-14 11:57:58 +02:00
|
|
|
Location to = npc.getOrAddTrait(CurrentLocation.class).getLocation();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (to == null) {
|
|
|
|
Messaging.sendError(player, Messages.TELEPORT_NPC_LOCATION_NOT_FOUND);
|
|
|
|
return;
|
|
|
|
}
|
2022-07-26 17:50:28 +02:00
|
|
|
if (!args.hasFlag('e')) {
|
|
|
|
to = to.clone().add(to.getDirection().setY(0));
|
|
|
|
to.setDirection(to.getDirection().multiply(-1)).setPitch(0);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
player.teleport(to, TeleportCause.COMMAND);
|
|
|
|
Messaging.sendTr(player, Messages.TELEPORTED_TO_NPC, npc.getName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2023-03-12 15:29:41 +01:00
|
|
|
usage = "tphere (cursor) -c(enter) -f(ront)",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Teleport a NPC to your location",
|
2023-03-12 15:29:41 +01:00
|
|
|
flags = "cf",
|
2020-02-14 15:48:40 +01:00
|
|
|
modifiers = { "tphere", "tph", "move" },
|
|
|
|
min = 1,
|
2020-08-03 14:30:50 +02:00
|
|
|
max = 2,
|
2020-02-14 15:48:40 +01:00
|
|
|
permission = "citizens.npc.tphere")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void tphere(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
2020-08-03 14:30:50 +02:00
|
|
|
Location to = args.getSenderLocation();
|
|
|
|
if (to == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
throw new ServerCommandException();
|
2020-08-03 14:30:50 +02:00
|
|
|
if (args.argsLength() > 1 && args.getString(1).equalsIgnoreCase("cursor")) {
|
|
|
|
if (!(sender instanceof Player))
|
|
|
|
throw new ServerCommandException();
|
|
|
|
Block target = ((Player) sender).getTargetBlock(null, 64);
|
|
|
|
if (target == null)
|
|
|
|
throw new CommandException(Messages.MISSING_TP_CURSOR_BLOCK);
|
2020-08-10 12:02:35 +02:00
|
|
|
to = target.getRelative(BlockFace.UP).getLocation();
|
2020-08-03 14:30:50 +02:00
|
|
|
}
|
2020-05-04 10:21:34 +02:00
|
|
|
if (!sender.hasPermission("citizens.npc.tphere.multiworld")
|
2023-11-05 13:58:37 +01:00
|
|
|
&& npc.getStoredLocation().getWorld() != args.getSenderLocation().getWorld())
|
2020-05-04 10:21:34 +02:00
|
|
|
throw new CommandException(Messages.CANNOT_TELEPORT_ACROSS_WORLDS);
|
2020-08-03 14:30:50 +02:00
|
|
|
if (args.hasFlag('c')) {
|
2020-08-10 12:02:35 +02:00
|
|
|
to = to.getBlock().getLocation();
|
|
|
|
to.setX(to.getX() + 0.5);
|
|
|
|
to.setZ(to.getZ() + 0.5);
|
2020-08-03 14:30:50 +02:00
|
|
|
}
|
2023-03-12 15:29:41 +01:00
|
|
|
if (args.hasFlag('f')) {
|
|
|
|
to = to.clone().add(to.getDirection().setY(0));
|
|
|
|
to.setDirection(to.getDirection().multiply(-1)).setPitch(0);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!npc.isSpawned()) {
|
2021-04-13 06:06:22 +02:00
|
|
|
NPCTeleportEvent event = new NPCTeleportEvent(npc, to);
|
|
|
|
Bukkit.getPluginManager().callEvent(event);
|
|
|
|
if (event.isCancelled())
|
|
|
|
return;
|
2020-08-03 14:30:50 +02:00
|
|
|
npc.spawn(to, SpawnReason.COMMAND);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2020-08-03 14:30:50 +02:00
|
|
|
npc.teleport(to, TeleportCause.COMMAND);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-07-21 18:54:49 +02:00
|
|
|
Messaging.sendTr(sender, Messages.NPC_TELEPORTED, npc.getName(),
|
|
|
|
Util.prettyPrintLocation(args.getSenderLocation()));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "tpto [player name|npc id] [player name|npc id]",
|
|
|
|
desc = "Teleport an NPC or player to another NPC or player",
|
|
|
|
modifiers = { "tpto" },
|
|
|
|
min = 2,
|
|
|
|
max = 3,
|
|
|
|
permission = "citizens.npc.tpto")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements
|
|
|
|
public void tpto(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
Entity from = null, to = null;
|
2019-10-19 07:42:37 +02:00
|
|
|
boolean firstWasPlayer = false;
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc != null) {
|
|
|
|
from = npc.getEntity();
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
int id = args.getInteger(1);
|
|
|
|
NPC fromNPC = CitizensAPI.getNPCRegistry().getById(id);
|
|
|
|
if (fromNPC != null) {
|
2019-10-19 07:42:37 +02:00
|
|
|
if (args.argsLength() == 2) {
|
|
|
|
to = fromNPC.getEntity();
|
2019-11-28 09:14:29 +01:00
|
|
|
} else {
|
|
|
|
from = fromNPC.getEntity();
|
2019-10-19 07:42:37 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
} catch (NumberFormatException e) {
|
2019-10-19 07:42:37 +02:00
|
|
|
if (args.argsLength() == 2) {
|
|
|
|
to = Bukkit.getPlayerExact(args.getString(1));
|
|
|
|
} else {
|
|
|
|
from = Bukkit.getPlayerExact(args.getString(1));
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
firstWasPlayer = true;
|
|
|
|
}
|
2019-11-28 09:10:35 +01:00
|
|
|
if (args.argsLength() == 3) {
|
|
|
|
try {
|
|
|
|
int id = args.getInteger(2);
|
|
|
|
NPC toNPC = CitizensAPI.getNPCRegistry().getById(id);
|
|
|
|
if (toNPC != null) {
|
|
|
|
to = toNPC.getEntity();
|
|
|
|
}
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
if (!firstWasPlayer) {
|
|
|
|
to = Bukkit.getPlayerExact(args.getString(2));
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (from == null)
|
|
|
|
throw new CommandException(Messages.FROM_ENTITY_NOT_FOUND);
|
|
|
|
if (to == null)
|
|
|
|
throw new CommandException(Messages.TO_ENTITY_NOT_FOUND);
|
|
|
|
from.teleport(to);
|
|
|
|
Messaging.sendTr(sender, Messages.TPTO_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2022-12-18 17:36:53 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "trackingrange [range]",
|
|
|
|
desc = "Sets the tracking range",
|
|
|
|
modifiers = { "trackingrange" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.trackingrange")
|
|
|
|
public void trackingrange(CommandContext args, CommandSender sender, NPC npc, @Arg(1) Integer range) {
|
|
|
|
if (range == null) {
|
|
|
|
npc.data().remove(NPC.Metadata.TRACKING_RANGE);
|
|
|
|
} else {
|
|
|
|
npc.data().setPersistent(NPC.Metadata.TRACKING_RANGE, range);
|
|
|
|
}
|
|
|
|
Messaging.sendTr(sender, Messages.TRACKING_RANGE_SET, range);
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "type [type]",
|
|
|
|
desc = "Sets an NPC's entity type",
|
|
|
|
modifiers = { "type" },
|
|
|
|
min = 2,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.type")
|
2022-09-07 21:01:39 +02:00
|
|
|
public void type(CommandContext args, CommandSender sender, NPC npc, @Arg(1) EntityType type)
|
|
|
|
throws CommandException {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (type == null)
|
|
|
|
throw new CommandException(Messages.INVALID_ENTITY_TYPE, args.getString(1));
|
|
|
|
npc.setBukkitEntityType(type);
|
|
|
|
Messaging.sendTr(sender, Messages.ENTITY_TYPE_SET, npc.getName(), args.getString(1));
|
|
|
|
}
|
|
|
|
|
2022-02-19 06:35:16 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "undo (all)",
|
|
|
|
desc = "Undoes the last action (currently only create/remove supported)",
|
|
|
|
modifiers = { "undo" },
|
|
|
|
min = 1,
|
|
|
|
max = 2,
|
|
|
|
permission = "citizens.npc.undo")
|
|
|
|
@Requirements
|
2022-09-07 21:01:39 +02:00
|
|
|
public void undo(CommandContext args, CommandSender sender, NPC npc,
|
|
|
|
@Arg(value = 1, completions = "all") String action) throws CommandException {
|
|
|
|
if ("all".equalsIgnoreCase(action)) {
|
2022-02-19 07:36:45 +01:00
|
|
|
while (history.undo(sender)) {
|
2022-02-19 06:35:16 +01:00
|
|
|
}
|
2022-02-19 07:36:45 +01:00
|
|
|
} else if (history.undo(sender)) {
|
2022-02-19 06:35:16 +01:00
|
|
|
Messaging.sendTr(sender, Messages.UNDO_SUCCESSFUL);
|
|
|
|
} else {
|
|
|
|
Messaging.sendTr(sender, Messages.UNDO_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-14 17:57:22 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "useitem (-o(ffhand))",
|
|
|
|
desc = "Sets an NPC to be using their held items",
|
|
|
|
modifiers = { "useitem" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "o",
|
|
|
|
permission = "citizens.npc.useitem")
|
|
|
|
public void useitem(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
boolean offhand = args.hasFlag('o');
|
|
|
|
if (offhand) {
|
2022-02-14 18:35:07 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.USING_OFFHAND_ITEM,
|
|
|
|
!npc.data().get(NPC.Metadata.USING_OFFHAND_ITEM, false));
|
2022-02-14 17:57:22 +01:00
|
|
|
Messaging.sendTr(sender, Messages.TOGGLED_USING_OFFHAND_ITEM,
|
2022-02-19 12:00:09 +01:00
|
|
|
Boolean.toString(npc.data().get(NPC.Metadata.USING_OFFHAND_ITEM)));
|
2022-02-14 17:57:22 +01:00
|
|
|
} else {
|
2022-02-14 18:35:07 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.USING_HELD_ITEM,
|
|
|
|
!npc.data().get(NPC.Metadata.USING_HELD_ITEM, false));
|
2022-02-19 12:00:09 +01:00
|
|
|
Messaging.sendTr(sender, Messages.TOGGLED_USING_HELD_ITEM,
|
|
|
|
Boolean.toString(npc.data().get(NPC.Metadata.USING_HELD_ITEM)));
|
2022-02-14 17:57:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-07-05 13:13:31 +02:00
|
|
|
usage = "vulnerable (-t(emporary))",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Toggles an NPC's vulnerability",
|
|
|
|
modifiers = { "vulnerable" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
flags = "t",
|
|
|
|
permission = "citizens.npc.vulnerable")
|
2017-12-30 08:36:36 +01:00
|
|
|
public void vulnerable(CommandContext args, CommandSender sender, NPC npc) {
|
2022-07-05 13:13:31 +02:00
|
|
|
boolean vulnerable = !npc.isProtected();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (args.hasFlag('t')) {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().set(NPC.Metadata.DEFAULT_PROTECTED, vulnerable);
|
2017-12-30 08:36:36 +01:00
|
|
|
} else {
|
2023-01-01 08:26:35 +01:00
|
|
|
npc.data().setPersistent(NPC.Metadata.DEFAULT_PROTECTED, vulnerable);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
String key = vulnerable ? Messages.VULNERABLE_STOPPED : Messages.VULNERABLE_SET;
|
|
|
|
Messaging.sendTr(sender, key, npc.getName());
|
|
|
|
}
|
|
|
|
|
2022-10-08 05:11:40 +02:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "wander",
|
|
|
|
desc = "Sets the NPC to wander around",
|
|
|
|
modifiers = { "wander" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.wander")
|
|
|
|
public void wander(CommandContext args, CommandSender sender, NPC npc) throws CommandException {
|
|
|
|
Waypoints trait = npc.getOrAddTrait(Waypoints.class);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (sender instanceof Player && Editor.hasEditor((Player) sender)) {
|
|
|
|
Editor.leave((Player) sender);
|
2023-09-20 16:05:05 +02:00
|
|
|
}
|
2022-11-06 16:19:08 +01:00
|
|
|
trait.setWaypointProvider(trait.getCurrentProviderName().equals("wander") ? "linear" : "wander");
|
2022-10-08 05:11:40 +02:00
|
|
|
Messaging.sendTr(sender, Messages.WAYPOINT_PROVIDER_SET, trait.getCurrentProviderName());
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
2022-09-08 07:28:14 +02:00
|
|
|
usage = "wither (--invulnerable [true|false]) (--arrow-shield [true|false])",
|
2020-02-14 15:48:40 +01:00
|
|
|
desc = "Sets wither modifiers",
|
|
|
|
modifiers = { "wither" },
|
|
|
|
min = 1,
|
|
|
|
requiresFlags = true,
|
|
|
|
max = 1,
|
|
|
|
permission = "citizens.npc.wither")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = { EntityType.WITHER })
|
2022-09-08 07:28:14 +02:00
|
|
|
public void wither(CommandContext args, CommandSender sender, NPC npc, @Flag("invulnerable") Boolean invulnerable,
|
|
|
|
@Flag("arrow-shield") Boolean arrows) throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
WitherTrait trait = npc.getOrAddTrait(WitherTrait.class);
|
2022-09-08 07:28:14 +02:00
|
|
|
if (invulnerable != null) {
|
|
|
|
trait.setInvulnerable(invulnerable);
|
|
|
|
}
|
|
|
|
if (arrows != null) {
|
|
|
|
trait.setBlocksArrows(arrows);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 15:48:40 +01:00
|
|
|
@Command(
|
|
|
|
aliases = { "npc" },
|
|
|
|
usage = "wolf (-s(itting) a(ngry) t(amed) i(nfo)) --collar [hex rgb color|name]",
|
|
|
|
desc = "Sets wolf modifiers",
|
|
|
|
modifiers = { "wolf" },
|
|
|
|
min = 1,
|
|
|
|
max = 1,
|
|
|
|
requiresFlags = true,
|
|
|
|
flags = "sati",
|
|
|
|
permission = "citizens.npc.wolf")
|
2017-12-30 08:36:36 +01:00
|
|
|
@Requirements(selected = true, ownership = true, types = EntityType.WOLF)
|
2022-09-06 20:11:07 +02:00
|
|
|
public void wolf(CommandContext args, CommandSender sender, NPC npc, @Flag("collar") String collar)
|
|
|
|
throws CommandException {
|
2020-09-14 11:57:58 +02:00
|
|
|
WolfModifiers trait = npc.getOrAddTrait(WolfModifiers.class);
|
2018-03-09 10:28:20 +01:00
|
|
|
if (args.hasFlag('a')) {
|
|
|
|
trait.setAngry(!trait.isAngry());
|
|
|
|
}
|
|
|
|
if (args.hasFlag('s')) {
|
|
|
|
trait.setSitting(!trait.isSitting());
|
|
|
|
}
|
|
|
|
if (args.hasFlag('t')) {
|
|
|
|
trait.setTamed(!trait.isTamed());
|
|
|
|
}
|
2022-09-06 20:11:07 +02:00
|
|
|
if (collar != null) {
|
|
|
|
String unparsed = collar;
|
2017-12-30 08:36:36 +01:00
|
|
|
DyeColor color = null;
|
|
|
|
try {
|
|
|
|
color = DyeColor.valueOf(unparsed.toUpperCase().replace(' ', '_'));
|
|
|
|
} catch (IllegalArgumentException e) {
|
|
|
|
try {
|
|
|
|
int rgb = Integer.parseInt(unparsed.replace("#", ""), 16);
|
|
|
|
color = DyeColor.getByColor(org.bukkit.Color.fromRGB(rgb));
|
|
|
|
} catch (NumberFormatException ex) {
|
|
|
|
throw new CommandException(Messages.COLLAR_COLOUR_NOT_RECOGNISED, unparsed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (color == null)
|
|
|
|
throw new CommandException(Messages.COLLAR_COLOUR_NOT_SUPPORTED, unparsed);
|
|
|
|
trait.setCollarColor(color);
|
|
|
|
}
|
2018-03-23 12:34:51 +01:00
|
|
|
Messaging.sendTr(sender, Messages.WOLF_TRAIT_UPDATED, npc.getName(), trait.isAngry(), trait.isSitting(),
|
|
|
|
trait.isTamed(), trait.getCollarColor().name());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2018-03-23 12:34:51 +01:00
|
|
|
}
|