2017-12-30 08:36:36 +01:00
package net.citizensnpcs.commands ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Collection ;
import java.util.Collections ;
import java.util.Comparator ;
import java.util.List ;
2019-05-24 12:32:51 +02:00
import java.util.Set ;
2017-12-30 08:36:36 +01:00
import java.util.UUID ;
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 ;
2017-12-30 08:36:36 +01:00
import org.bukkit.World ;
import org.bukkit.command.BlockCommandSender ;
import org.bukkit.command.CommandSender ;
import org.bukkit.command.ConsoleCommandSender ;
import org.bukkit.entity.Ageable ;
import org.bukkit.entity.Entity ;
import org.bukkit.entity.EntityType ;
import org.bukkit.entity.Horse.Color ;
import org.bukkit.entity.Horse.Style ;
import org.bukkit.entity.ItemFrame ;
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 ;
import com.google.common.base.Joiner ;
import com.google.common.base.Splitter ;
import com.google.common.collect.Iterables ;
import com.google.common.collect.Lists ;
2019-09-17 13:30:09 +02:00
import com.mysql.jdbc.StringUtils ;
2017-12-30 08:36:36 +01:00
import net.citizensnpcs.Citizens ;
import net.citizensnpcs.Settings.Setting ;
import net.citizensnpcs.api.CitizensAPI ;
import net.citizensnpcs.api.ai.speech.SpeechContext ;
import net.citizensnpcs.api.command.Command ;
import net.citizensnpcs.api.command.CommandContext ;
import net.citizensnpcs.api.command.CommandMessages ;
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 ;
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 ;
2017-12-30 08:36:36 +01:00
import net.citizensnpcs.api.npc.NPC ;
import net.citizensnpcs.api.npc.NPCRegistry ;
import net.citizensnpcs.api.trait.Trait ;
import net.citizensnpcs.api.trait.trait.Inventory ;
import net.citizensnpcs.api.trait.trait.MobType ;
import net.citizensnpcs.api.trait.trait.Owner ;
import net.citizensnpcs.api.trait.trait.Spawned ;
import net.citizensnpcs.api.trait.trait.Speech ;
import net.citizensnpcs.api.util.Colorizer ;
import net.citizensnpcs.api.util.Messaging ;
import net.citizensnpcs.api.util.Paginator ;
import net.citizensnpcs.npc.EntityControllers ;
import net.citizensnpcs.npc.NPCSelector ;
import net.citizensnpcs.npc.Template ;
import net.citizensnpcs.npc.skin.SkinnableEntity ;
import net.citizensnpcs.trait.Age ;
import net.citizensnpcs.trait.Anchors ;
import net.citizensnpcs.trait.ArmorStandTrait ;
2019-09-23 14:29:31 +02:00
import net.citizensnpcs.trait.CommandTrait ;
2017-12-30 08:36:36 +01:00
import net.citizensnpcs.trait.Controllable ;
import net.citizensnpcs.trait.CurrentLocation ;
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 ;
import net.citizensnpcs.trait.HorseModifiers ;
import net.citizensnpcs.trait.LookClose ;
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 ;
import net.citizensnpcs.trait.Poses ;
import net.citizensnpcs.trait.Powered ;
import net.citizensnpcs.trait.RabbitType ;
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.ScriptTrait ;
import net.citizensnpcs.trait.SheepTrait ;
import net.citizensnpcs.trait.SkinLayers ;
import net.citizensnpcs.trait.SkinLayers.Layer ;
import net.citizensnpcs.trait.SlimeSize ;
import net.citizensnpcs.trait.VillagerProfession ;
import net.citizensnpcs.trait.WitherTrait ;
import net.citizensnpcs.trait.WolfModifiers ;
import net.citizensnpcs.util.Anchor ;
import net.citizensnpcs.util.Messages ;
import net.citizensnpcs.util.NMS ;
import net.citizensnpcs.util.StringHelper ;
import net.citizensnpcs.util.Util ;
@Requirements ( selected = true , ownership = true )
public class NPCCommands {
private final NPCSelector selector ;
public NPCCommands ( Citizens plugin ) {
selector = plugin . getNPCSelector ( ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " age [age] (-l) " , 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 {
if ( ! npc . isSpawned ( ) | | ( ! ( npc . getEntity ( ) instanceof Ageable ) & & ! ( npc . getEntity ( ) instanceof Zombie ) ) )
throw new CommandException ( Messages . MOBTYPE_CANNOT_BE_AGED , npc . getName ( ) ) ;
Age trait = npc . getTrait ( Age . class ) ;
boolean toggleLock = args . hasFlag ( 'l' ) ;
if ( toggleLock ) {
Messaging . sendTr ( sender , trait . toggle ( ) ? Messages . AGE_LOCKED : Messages . AGE_UNLOCKED ) ;
}
if ( args . argsLength ( ) < = 1 ) {
if ( ! toggleLock )
trait . describe ( sender ) ;
return ;
}
int age = 0 ;
try {
age = args . getInteger ( 1 ) ;
if ( age > 0 ) {
throw new CommandException ( Messages . INVALID_AGE ) ;
}
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 ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " anchor (--save [name]|--assume [name]|--remove [name]) (-a)(-c) " , desc = " Changes/Saves/Lists NPC's location anchor(s) " , flags = " ac " , modifiers = {
" anchor " } , min = 1 , max = 3 , permission = " citizens.npc.anchor " )
2017-12-30 08:36:36 +01:00
public void anchor ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
Anchors trait = npc . getTrait ( Anchors . class ) ;
if ( args . hasValueFlag ( " save " ) ) {
if ( args . getFlag ( " save " ) . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_ANCHOR_NAME ) ;
if ( args . getSenderLocation ( ) = = null )
throw new ServerCommandException ( ) ;
if ( args . hasFlag ( 'c' ) ) {
if ( trait . addAnchor ( args . getFlag ( " save " ) , args . getSenderTargetBlockLocation ( ) ) ) {
Messaging . sendTr ( sender , Messages . ANCHOR_ADDED ) ;
} else
throw new CommandException ( Messages . ANCHOR_ALREADY_EXISTS , args . getFlag ( " save " ) ) ;
} else {
if ( trait . addAnchor ( args . getFlag ( " save " ) , args . getSenderLocation ( ) ) ) {
Messaging . sendTr ( sender , Messages . ANCHOR_ADDED ) ;
} else
throw new CommandException ( Messages . ANCHOR_ALREADY_EXISTS , args . getFlag ( " save " ) ) ;
}
} else if ( args . hasValueFlag ( " assume " ) ) {
if ( args . getFlag ( " assume " ) . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_ANCHOR_NAME ) ;
Anchor anchor = trait . getAnchor ( args . getFlag ( " assume " ) ) ;
if ( anchor = = null )
throw new CommandException ( Messages . ANCHOR_MISSING , args . getFlag ( " assume " ) ) ;
npc . teleport ( anchor . getLocation ( ) , TeleportCause . COMMAND ) ;
} else if ( args . hasValueFlag ( " remove " ) ) {
if ( args . getFlag ( " remove " ) . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_ANCHOR_NAME ) ;
if ( trait . removeAnchor ( trait . getAnchor ( args . getFlag ( " remove " ) ) ) )
Messaging . sendTr ( sender , Messages . ANCHOR_REMOVED ) ;
else
throw new CommandException ( Messages . ANCHOR_MISSING , args . getFlag ( " remove " ) ) ;
} else if ( ! args . hasFlag ( 'a' ) ) {
2019-09-24 16:05:10 +02:00
Paginator paginator = new Paginator ( ) . header ( " Anchors " ) . console ( sender instanceof ConsoleCommandSender ) ;
2017-12-30 08:36:36 +01:00
paginator . addLine ( " <e>Key: <a>ID <b>Name <c>World <d>Location (X,Y,Z) " ) ;
for ( int i = 0 ; i < trait . getAnchors ( ) . size ( ) ; i + + ) {
if ( trait . getAnchors ( ) . get ( i ) . isLoaded ( ) ) {
String line = " <a> " + i + " <b> " + trait . getAnchors ( ) . get ( i ) . getName ( ) + " <c> "
+ trait . getAnchors ( ) . get ( i ) . getLocation ( ) . getWorld ( ) . getName ( ) + " <d> "
+ 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 ( ) ;
String line = " <a> " + i + " <b> " + trait . getAnchors ( ) . get ( i ) . getName ( ) + " <c> " + parts [ 0 ]
+ " <d> " + parts [ 1 ] + " , " + parts [ 2 ] + " , " + parts [ 3 ] + " <f>(unloaded) " ;
paginator . addLine ( line ) ;
}
}
int page = args . getInteger ( 1 , 1 ) ;
if ( ! paginator . sendPage ( sender , page ) )
throw new CommandException ( Messages . COMMAND_PAGE_MISSING ) ;
}
// Assume Player's position
if ( ! args . hasFlag ( 'a' ) )
return ;
if ( sender instanceof ConsoleCommandSender )
throw new ServerCommandException ( ) ;
npc . teleport ( args . getSenderLocation ( ) , TeleportCause . COMMAND ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " armorstand --visible [visible] --small [small] --gravity [gravity] --arms [arms] --baseplate [baseplate] " , desc = " Edit armorstand properties " , modifiers = {
" armorstand " } , min = 1 , max = 1 )
2017-12-30 08:36:36 +01:00
@Requirements ( selected = true , ownership = true , types = EntityType . ARMOR_STAND )
public void armorstand ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
ArmorStandTrait trait = npc . getTrait ( ArmorStandTrait . class ) ;
if ( args . hasValueFlag ( " visible " ) ) {
trait . setVisible ( Boolean . valueOf ( args . getFlag ( " visible " ) ) ) ;
}
if ( args . hasValueFlag ( " small " ) ) {
trait . setSmall ( Boolean . valueOf ( args . getFlag ( " small " ) ) ) ;
}
if ( args . hasValueFlag ( " gravity " ) ) {
trait . setGravity ( Boolean . valueOf ( args . getFlag ( " gravity " ) ) ) ;
}
if ( args . hasValueFlag ( " arms " ) ) {
trait . setHasArms ( Boolean . valueOf ( args . getFlag ( " arms " ) ) ) ;
}
if ( args . hasValueFlag ( " baseplate " ) ) {
trait . setHasBaseplate ( Boolean . valueOf ( args . getFlag ( " baseplate " ) ) ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " collidable " , desc = " Toggles an NPC's collidability " , modifiers = {
" collidable " } , min = 1 , max = 1 , permission = " citizens.npc.collidable " )
2017-12-30 08:36:36 +01:00
@Requirements ( ownership = true , selected = true , types = { EntityType . PLAYER } )
public void collidable ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
npc . data ( ) . setPersistent ( NPC . COLLIDABLE_METADATA , ! npc . data ( ) . get ( NPC . COLLIDABLE_METADATA , true ) ) ;
Messaging . sendTr ( sender ,
2020-01-17 10:11:23 +01:00
npc . data ( ) . < Boolean > get ( NPC . COLLIDABLE_METADATA ) ? Messages . COLLIDABLE_SET : Messages . COLLIDABLE_UNSET ,
2017-12-30 08:36:36 +01:00
npc . getName ( ) ) ;
2018-03-09 16:30:28 +01:00
2017-12-30 08:36:36 +01:00
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " command|cmd (add [command] | remove [id]) (-l[eft]/-r[ight]) (-p[layer] -o[p]) " , desc = " Controls commands which will be run when clicking on an NPC " , modifiers = {
" command " , " cmd " } , min = 1 , flags = " lrpo " , permission = " citizens.npc.command " )
2019-09-23 14:29:31 +02:00
public void command ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
CommandTrait commands = npc . getTrait ( CommandTrait . class ) ;
if ( args . argsLength ( ) = = 1 ) {
commands . describe ( sender ) ;
} else if ( args . getString ( 1 ) . equalsIgnoreCase ( " add " ) ) {
if ( args . argsLength ( ) = = 2 )
throw new CommandUsageException ( ) ;
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 ;
2019-12-29 14:14:38 +01:00
int id = commands . addCommand ( command , hand , args . hasFlag ( 'p' ) , args . hasFlag ( 'o' ) ) ;
2019-09-23 14:29:31 +02:00
Messaging . sendTr ( sender , Messages . COMMAND_ADDED , command , id ) ;
} else if ( args . getString ( 1 ) . equalsIgnoreCase ( " remove " ) ) {
if ( args . argsLength ( ) = = 2 )
throw new CommandUsageException ( ) ;
int id = args . getInteger ( 2 ) ;
if ( ! commands . hasCommandId ( id ) )
throw new CommandException ( Messages . COMMAND_UNKNOWN_COMMAND_ID , id ) ;
commands . removeCommandById ( id ) ;
Messaging . sendTr ( sender , Messages . COMMAND_REMOVED , id ) ;
} else {
throw new CommandUsageException ( ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " controllable|control (-m(ount),-y,-n,-o) " , 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 {
if ( ( npc . isSpawned ( ) & & ! sender . hasPermission (
" citizens.npc.controllable. " + npc . getEntity ( ) . getType ( ) . name ( ) . toLowerCase ( ) . replace ( " _ " , " " ) ) )
| | ! sender . hasPermission ( " citizens.npc.controllable " ) )
throw new NoPermissionsException ( ) ;
if ( ! npc . hasTrait ( Controllable . class ) ) {
npc . addTrait ( new Controllable ( false ) ) ;
}
Controllable trait = npc . getTrait ( Controllable . class ) ;
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-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " copy (--name newname) " , desc = " Copies an NPC " , modifiers = {
" copy " } , min = 1 , max = 1 , permission = " citizens.npc.copy " )
2017-12-30 08:36:36 +01:00
public void copy ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
String name = args . getFlag ( " name " , npc . getFullName ( ) ) ;
NPC copy = npc . clone ( ) ;
if ( ! copy . getFullName ( ) . equals ( name ) ) {
copy . setName ( name ) ;
}
if ( copy . isSpawned ( ) & & args . getSenderLocation ( ) ! = null ) {
Location location = args . getSenderLocation ( ) ;
location . getChunk ( ) . load ( ) ;
copy . teleport ( location , TeleportCause . COMMAND ) ;
copy . getTrait ( CurrentLocation . class ) . setLocation ( location ) ;
}
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. " ;
if ( ! event . getCancelReason ( ) . isEmpty ( ) )
reason + = " Reason: " + event . getCancelReason ( ) ;
throw new CommandException ( reason ) ;
}
Messaging . sendTr ( sender , Messages . NPC_COPIED , npc . getName ( ) ) ;
selector . select ( sender , copy ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " create [name] ((-b,u) --at (x:y:z:world) --type (type) --trait ('trait1, trait2...') --b (behaviours)) " , desc = " Create a new NPC " , flags = " bu " , modifiers = {
" create " } , min = 2 , permission = " citizens.npc.create " )
2017-12-30 08:36:36 +01:00
@Requirements
public void create ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
String name = Colorizer . parseColors ( args . getJoinedStrings ( 1 ) . trim ( ) ) ;
EntityType type = EntityType . PLAYER ;
if ( args . hasValueFlag ( " type " ) ) {
String inputType = args . getFlag ( " type " ) ;
type = Util . matchEntityType ( inputType ) ;
if ( type = = null ) {
throw new CommandException ( Messaging . tr ( Messages . NPC_CREATE_INVALID_MOBTYPE , inputType ) ) ;
} else if ( ! EntityControllers . controllerExistsForType ( type ) ) {
throw new CommandException ( Messaging . tr ( Messages . NPC_CREATE_MISSING_MOBTYPE , inputType ) ) ;
}
}
int nameLength = type = = EntityType . PLAYER ? 46 : 64 ;
if ( name . length ( ) > nameLength ) {
Messaging . sendErrorTr ( sender , Messages . NPC_NAME_TOO_LONG ) ;
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 ( ) ;
2019-01-18 17:18:43 +01:00
npc = CitizensAPI . getNPCRegistry ( ) . createNPC ( type , name ) ;
2017-12-30 08:36:36 +01:00
String msg = " You created [[ " + npc . getName ( ) + " ]] " ;
int age = 0 ;
if ( args . hasFlag ( 'b' ) ) {
if ( ! Ageable . class . isAssignableFrom ( type . getEntityClass ( ) ) )
Messaging . sendErrorTr ( sender , Messages . MOBTYPE_CANNOT_BE_AGED ,
type . name ( ) . toLowerCase ( ) . replace ( " _ " , " - " ) ) ;
else {
age = - 24000 ;
msg + = " as a baby " ;
}
}
// Initialize necessary traits
if ( ! Setting . SERVER_OWNS_NPCS . asBoolean ( ) ) {
npc . getTrait ( Owner . class ) . setOwner ( sender ) ;
}
npc . getTrait ( MobType . class ) . setType ( type ) ;
Location spawnLoc = null ;
if ( sender instanceof Player ) {
spawnLoc = args . getSenderLocation ( ) ;
} else if ( sender instanceof BlockCommandSender ) {
spawnLoc = args . getSenderLocation ( ) ;
}
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. " ;
if ( ! event . getCancelReason ( ) . isEmpty ( ) )
reason + = " Reason: " + event . getCancelReason ( ) ;
throw new CommandException ( reason ) ;
}
if ( args . hasValueFlag ( " at " ) ) {
spawnLoc = CommandContext . parseLocation ( args . getSenderLocation ( ) , args . getFlag ( " 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 ) ;
}
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
}
if ( args . hasValueFlag ( " trait " ) ) {
Iterable < String > parts = Splitter . on ( ',' ) . trimResults ( ) . split ( args . getFlag ( " trait " ) ) ;
StringBuilder builder = new StringBuilder ( ) ;
for ( String tr : parts ) {
Trait trait = CitizensAPI . getTraitFactory ( ) . getTrait ( tr ) ;
if ( trait = = null )
continue ;
npc . addTrait ( trait ) ;
builder . append ( StringHelper . wrap ( tr ) + " , " ) ;
}
if ( builder . length ( ) > 0 )
builder . delete ( builder . length ( ) - 2 , builder . length ( ) ) ;
msg + = " with traits " + builder . toString ( ) ;
}
if ( args . hasValueFlag ( " template " ) ) {
Iterable < String > parts = Splitter . on ( ',' ) . trimResults ( ) . split ( args . getFlag ( " template " ) ) ;
StringBuilder builder = new StringBuilder ( ) ;
for ( String part : parts ) {
Template template = Template . byName ( part ) ;
if ( template = = null )
continue ;
template . apply ( npc ) ;
builder . append ( StringHelper . wrap ( part ) + " , " ) ;
}
if ( builder . length ( ) > 0 )
builder . delete ( builder . length ( ) - 2 , builder . length ( ) ) ;
msg + = " with templates " + builder . toString ( ) ;
}
// Set age after entity spawns
if ( npc . getEntity ( ) instanceof Ageable ) {
npc . getTrait ( Age . class ) . setAge ( age ) ;
}
selector . select ( sender , npc ) ;
Messaging . send ( sender , msg + '.' ) ;
}
2020-01-17 10:11:23 +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
public void despawn ( final CommandContext args , final CommandSender sender , NPC npc ) throws CommandException {
NPCCommandSelector . Callback callback = new NPCCommandSelector . Callback ( ) {
@Override
public void run ( NPC npc ) throws CommandException {
if ( npc = = null ) {
throw new CommandException ( Messages . NO_NPC_WITH_ID_FOUND , args . getString ( 1 ) ) ;
}
npc . getTrait ( Spawned . class ) . setSpawned ( false ) ;
npc . despawn ( DespawnReason . REMOVAL ) ;
Messaging . sendTr ( sender , Messages . NPC_DESPAWNED , npc . getName ( ) ) ;
}
} ;
if ( npc = = null | | args . argsLength ( ) = = 2 ) {
if ( args . argsLength ( ) < 2 ) {
throw new CommandException ( Messages . COMMAND_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 ) ;
}
}
2020-01-17 10:11:23 +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 } )
2017-12-30 08:36:36 +01:00
public void flyable ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
boolean flyable = args . argsLength ( ) = = 2 ? args . getString ( 1 ) . equals ( " true " ) : ! npc . isFlyable ( ) ;
npc . setFlyable ( flyable ) ;
2018-06-29 16:35:13 +02:00
flyable = npc . isFlyable ( ) ; // may not have applied, eg bats always flyable
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , flyable ? Messages . FLYABLE_SET : Messages . FLYABLE_UNSET , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " follow (player name) (-p[rotect]) " , desc = " Toggles NPC following you " , flags = " p " , modifiers = {
" follow " } , min = 1 , max = 2 , permission = " citizens.npc.follow " )
2018-10-06 11:11:57 +02:00
public void follow ( CommandContext args , Player sender , NPC npc ) throws CommandException {
boolean protect = args . hasFlag ( 'p' ) ;
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 ) ;
if ( player = = null ) {
throw new CommandException ( ) ;
}
boolean following = npc . getTrait ( FollowTrait . class ) . toggle ( player , protect ) ;
Messaging . sendTr ( sender , following ? Messages . FOLLOW_SET : Messages . FOLLOW_UNSET , npc . getName ( ) ,
player . getName ( ) ) ;
2018-10-06 11:11:57 +02:00
}
2020-01-17 10:11:23 +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 } )
public void gamemode ( CommandContext args , CommandSender sender , NPC npc ) {
Player player = ( Player ) npc . getEntity ( ) ;
if ( args . argsLength ( ) = = 1 ) {
Messaging . sendTr ( sender , Messages . GAMEMODE_DESCRIBE , npc . getName ( ) ,
player . getGameMode ( ) . name ( ) . toLowerCase ( ) ) ;
return ;
}
GameMode mode = null ;
try {
int value = args . getInteger ( 1 ) ;
mode = GameMode . getByValue ( value ) ;
} catch ( NumberFormatException ex ) {
try {
2018-06-27 06:00:03 +02:00
mode = GameMode . valueOf ( args . getString ( 1 ) . toUpperCase ( ) ) ;
2017-12-30 08:36:36 +01:00
} catch ( IllegalArgumentException e ) {
}
}
if ( mode = = null ) {
Messaging . sendErrorTr ( sender , Messages . GAMEMODE_INVALID , args . getString ( 1 ) ) ;
return ;
}
2018-11-12 07:53:52 +01:00
npc . getTrait ( GameModeTrait . class ) . setGameMode ( mode ) ;
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , Messages . GAMEMODE_SET , mode . name ( ) . toLowerCase ( ) ) ;
}
2020-01-17 10:11:23 +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 )
public void glowing ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
if ( args . hasValueFlag ( " color " ) ) {
ChatColor chatColor = Util . matchEnum ( ChatColor . values ( ) , args . getFlag ( " color " ) ) ;
if ( ! ( npc . getEntity ( ) instanceof Player ) )
2019-09-17 13:48:21 +02:00
throw new CommandException ( Messages . GLOWING_COLOR_PLAYER_ONLY ) ;
2019-07-12 09:39:38 +02:00
npc . getTrait ( ScoreboardTrait . class ) . setColor ( chatColor ) ;
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , Messages . GLOWING_COLOR_SET , npc . getName ( ) ,
chatColor = = null ? ChatColor . WHITE + " white " : chatColor + Util . prettyEnum ( chatColor ) ) ;
return ;
}
npc . data ( ) . setPersistent ( NPC . GLOWING_METADATA , ! npc . data ( ) . get ( NPC . GLOWING_METADATA , false ) ) ;
boolean glowing = npc . data ( ) . get ( NPC . GLOWING_METADATA ) ;
Messaging . sendTr ( sender , glowing ? Messages . GLOWING_SET : Messages . GLOWING_UNSET , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +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 ) {
boolean enabled = npc . getTrait ( Gravity . class ) . toggle ( ) ;
String key = ! enabled ? Messages . GRAVITY_ENABLED : Messages . GRAVITY_DISABLED ;
Messaging . sendTr ( sender , key , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " horse|llama|donkey|mule (--color color) (--type type) (--style style) (-cb) " , 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. " , modifiers = {
" horse " , " llama " , " donkey " ,
" mule " } , min = 1 , max = 1 , flags = " cb " , permission = " citizens.npc.horse " )
2019-05-24 12:32:51 +02:00
@Requirements ( selected = true , ownership = true )
2017-12-30 08:36:36 +01:00
public void horse ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
2019-05-24 12:32:51 +02:00
Set < EntityType > allowedTypes = Util . optionalEntitySet ( " HORSE " , " LLAMA " , " DONKEY " , " MULE " , " TRADER_LLAMA " ) ;
EntityType type = npc . getTrait ( MobType . class ) . getType ( ) ;
if ( ! allowedTypes . contains ( type ) ) {
throw new CommandException ( CommandMessages . REQUIREMENTS_INVALID_MOB_TYPE , Util . prettyEnum ( type ) ) ;
}
2017-12-30 08:36:36 +01:00
HorseModifiers horse = npc . getTrait ( HorseModifiers . class ) ;
String output = " " ;
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
String colorRaw = args . getFlag ( " color " , args . getFlag ( " colour " ) ) ;
Color color = Util . matchEnum ( Color . values ( ) , colorRaw ) ;
if ( color = = null ) {
String valid = Util . listValuesPretty ( Color . values ( ) ) ;
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
Style style = Util . matchEnum ( Style . values ( ) , args . getFlag ( " style " ) ) ;
if ( style = = null ) {
String valid = Util . listValuesPretty ( Style . values ( ) ) ;
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 {
sender . sendMessage ( output ) ;
}
}
2020-01-17 10:11:23 +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 ) {
Messaging . send ( sender , npc . getId ( ) ) ;
}
2020-01-17 10:11:23 +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 ) {
npc . getTrait ( Inventory . class ) . openInventory ( ( Player ) sender ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " item [item] (data) " , desc = " Sets the NPC's item " , modifiers = {
" item " , } , min = 2 , max = 3 , flags = " " , permission = " citizens.npc.item " )
@Requirements ( selected = true , ownership = true , types = { EntityType . DROPPED_ITEM , EntityType . ITEM_FRAME ,
EntityType . FALLING_BLOCK } )
2017-12-30 08:36:36 +01:00
public void item ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
Material mat = Material . matchMaterial ( args . getString ( 1 ) ) ;
if ( mat = = null )
throw new CommandException ( Messages . UNKNOWN_MATERIAL ) ;
int data = args . getInteger ( 2 , 0 ) ;
npc . data ( ) . setPersistent ( NPC . ITEM_ID_METADATA , mat . name ( ) ) ;
npc . data ( ) . setPersistent ( NPC . ITEM_DATA_METADATA , data ) ;
switch ( npc . getEntity ( ) . getType ( ) ) {
2020-01-17 10:11:23 +01:00
case DROPPED_ITEM :
( ( org . bukkit . entity . Item ) npc . getEntity ( ) ) . getItemStack ( ) . setType ( mat ) ;
break ;
case ITEM_FRAME :
( ( ItemFrame ) npc . getEntity ( ) ) . getItem ( ) . setType ( mat ) ;
break ;
default :
break ;
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
}
Messaging . sendTr ( sender , Messages . ITEM_SET , Util . prettyEnum ( mat ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " leashable " , desc = " Toggles leashability " , modifiers = {
" leashable " } , min = 1 , max = 1 , flags = " t " , permission = " citizens.npc.leashable " )
2017-12-30 08:36:36 +01:00
public void leashable ( CommandContext args , CommandSender sender , NPC npc ) {
boolean vulnerable = ! npc . data ( ) . get ( NPC . LEASH_PROTECTED_METADATA , true ) ;
if ( args . hasFlag ( 't' ) ) {
npc . data ( ) . set ( NPC . LEASH_PROTECTED_METADATA , vulnerable ) ;
} else {
npc . data ( ) . setPersistent ( NPC . LEASH_PROTECTED_METADATA , vulnerable ) ;
}
String key = vulnerable ? Messages . LEASHABLE_STOPPED : Messages . LEASHABLE_SET ;
Messaging . sendTr ( sender , key , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +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
public void list ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
NPCRegistry source = args . hasValueFlag ( " registry " ) ? CitizensAPI . getNamedNPCRegistry ( args . getFlag ( " 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 ( ) ;
List < NPC > npcs = new ArrayList < NPC > ( ) ;
if ( args . hasFlag ( 'a' ) ) {
for ( NPC add : source . sorted ( ) ) {
npcs . add ( add ) ;
}
} else if ( args . getValueFlags ( ) . size ( ) = = 0 & & sender instanceof Player ) {
for ( NPC add : source . sorted ( ) ) {
if ( ! npcs . contains ( add ) & & add . getTrait ( Owner . class ) . isOwnedBy ( sender ) ) {
npcs . add ( add ) ;
}
}
} else {
if ( args . hasValueFlag ( " owner " ) ) {
String name = args . getFlag ( " owner " ) ;
for ( NPC add : source . sorted ( ) ) {
if ( ! npcs . contains ( add ) & & add . getTrait ( Owner . class ) . isOwnedBy ( name ) ) {
npcs . add ( add ) ;
}
}
}
if ( args . hasValueFlag ( " type " ) ) {
EntityType type = Util . matchEntityType ( args . getFlag ( " type " ) ) ;
if ( type = = null )
throw new CommandException ( Messages . COMMAND_INVALID_MOBTYPE , type ) ;
for ( NPC add : source ) {
if ( ! npcs . contains ( add ) & & add . getTrait ( MobType . class ) . getType ( ) = = type )
npcs . add ( add ) ;
}
}
}
2019-09-24 16:05:10 +02:00
Paginator paginator = new Paginator ( ) . header ( " NPCs " ) . console ( sender instanceof ConsoleCommandSender ) ;
2017-12-30 08:36:36 +01:00
paginator . addLine ( " <e>Key: <a>ID <b>Name " ) ;
for ( int i = 0 ; i < npcs . size ( ) ; i + = 2 ) {
String line = " <a> " + npcs . get ( i ) . getId ( ) + " <b> " + npcs . get ( i ) . getName ( ) ;
if ( npcs . size ( ) > = i + 2 )
line + = " " + " <a> " + npcs . get ( i + 1 ) . getId ( ) + " <b> " + npcs . get ( i + 1 ) . getName ( ) ;
paginator . addLine ( line ) ;
}
int page = args . getInteger ( 1 , 1 ) ;
if ( ! paginator . sendPage ( sender , page ) )
throw new CommandException ( Messages . COMMAND_PAGE_MISSING ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " lookclose --(random|r)look [true|false] --(random|r)pitchrange [min,max] --(random|r)yawrange [min,max] " , desc = " Toggle whether a NPC will look when a player is near " , modifiers = {
" lookclose " , " look " , " rotate " } , min = 1 , max = 1 , permission = " citizens.npc.lookclose " )
2019-04-26 15:14:15 +02:00
public void lookClose ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
boolean toggle = true ;
if ( args . hasAnyValueFlag ( " randomlook " , " rlook " ) ) {
boolean enableRandomLook = Boolean . parseBoolean ( args . getFlag ( " randomlook " , args . getFlag ( " rlook " ) ) ) ;
npc . getTrait ( LookClose . class ) . setRandomLook ( enableRandomLook ) ;
Messaging . sendTr ( sender ,
enableRandomLook ? Messages . LOOKCLOSE_RANDOM_SET : Messages . LOOKCLOSE_RANDOM_STOPPED ,
npc . getName ( ) ) ;
toggle = false ;
}
if ( args . hasAnyValueFlag ( " randomlookdelay " , " rlookdelay " ) ) {
int delay = Integer . parseInt ( args . getFlag ( " randomlookdelay " , args . getFlag ( " rlookdelay " ) ) ) ;
delay = Math . max ( 1 , delay ) ;
npc . getTrait ( LookClose . class ) . setRandomLookDelay ( delay ) ;
Messaging . sendTr ( sender , Messages . LOOKCLOSE_RANDOM_DELAY_SET , npc . getName ( ) , delay ) ;
toggle = false ;
}
if ( args . hasAnyValueFlag ( " randompitchrange " , " rpitchrange " ) ) {
String flag = args . getFlag ( " randompitchrange " , args . getFlag ( " rpitchrange " ) ) ;
try {
String [ ] parts = flag . split ( " , " ) ;
float min = Float . parseFloat ( parts [ 0 ] ) , max = Float . parseFloat ( parts [ 1 ] ) ;
if ( min > max )
throw new IllegalArgumentException ( ) ;
npc . getTrait ( LookClose . class ) . setRandomLookPitchRange ( min , max ) ;
} catch ( Exception e ) {
throw new CommandException ( Messaging . tr ( Messages . ERROR_SETTING_LOOKCLOSE_RANGE , flag ) ) ;
}
Messaging . sendTr ( sender , Messages . LOOKCLOSE_RANDOM_PITCH_RANGE_SET , npc . getName ( ) , flag ) ;
toggle = false ;
}
if ( args . hasAnyValueFlag ( " randomyawrange " , " ryawrange " ) ) {
String flag = args . getFlag ( " randomyawrange " , args . getFlag ( " ryawrange " ) ) ;
try {
String [ ] parts = flag . split ( " , " ) ;
float min = Float . parseFloat ( parts [ 0 ] ) , max = Float . parseFloat ( parts [ 1 ] ) ;
if ( min > max )
throw new IllegalArgumentException ( ) ;
npc . getTrait ( LookClose . class ) . setRandomLookYawRange ( min , max ) ;
} catch ( Exception e ) {
throw new CommandException ( Messaging . tr ( Messages . ERROR_SETTING_LOOKCLOSE_RANGE , flag ) ) ;
}
Messaging . sendTr ( sender , Messages . LOOKCLOSE_RANDOM_YAW_RANGE_SET , npc . getName ( ) , flag ) ;
toggle = false ;
}
if ( toggle ) {
Messaging . sendTr ( sender ,
npc . getTrait ( LookClose . class ) . toggle ( ) ? Messages . LOOKCLOSE_SET : Messages . LOOKCLOSE_STOPPED ,
npc . getName ( ) ) ;
}
2017-12-30 08:36:36 +01:00
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " metadata set|get|remove [key] (value) (-t(emporary)) " , desc = " Manages NPC metadata " , modifiers = {
" metadata " } , flags = " t " , min = 2 , max = 4 , permission = " citizens.npc.metadata " )
2017-12-30 08:36:36 +01:00
@Requirements ( selected = true , ownership = true )
public void metadata ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
String command = args . getString ( 1 ) . toLowerCase ( ) ;
if ( command . equals ( " set " ) ) {
if ( args . argsLength ( ) ! = 4 )
throw new CommandException ( ) ;
if ( args . hasFlag ( 't' ) ) {
npc . data ( ) . set ( args . getString ( 2 ) , args . getString ( 3 ) ) ;
} else {
npc . data ( ) . setPersistent ( args . getString ( 2 ) , args . getString ( 3 ) ) ;
}
Messaging . sendTr ( sender , Messages . METADATA_SET , args . getString ( 2 ) , args . getString ( 3 ) ) ;
2019-12-23 03:03:08 +01:00
} else if ( command . equals ( " get " ) ) {
2017-12-30 08:36:36 +01:00
if ( args . argsLength ( ) ! = 3 ) {
throw new CommandException ( ) ;
}
Messaging . send ( sender , npc . data ( ) . get ( args . getString ( 2 ) , " null " ) ) ;
2019-12-23 03:03:08 +01:00
} else if ( command . equals ( " remove " ) ) {
2017-12-30 08:36:36 +01:00
if ( args . argsLength ( ) ! = 3 ) {
throw new CommandException ( ) ;
}
2019-12-23 03:03:08 +01:00
npc . data ( ) . remove ( args . getString ( 2 ) ) ;
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , Messages . METADATA_UNSET , args . getString ( 2 ) ) ;
}
}
2020-01-17 10:11:23 +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 } )
2017-12-30 08:36:36 +01:00
public void minecart ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
if ( args . hasValueFlag ( " item " ) ) {
String raw = args . getFlag ( " item " ) ;
int data = 0 ;
if ( raw . contains ( " : " ) ) {
int dataIndex = raw . indexOf ( ':' ) ;
data = Integer . parseInt ( raw . substring ( dataIndex + 1 ) ) ;
raw = raw . substring ( 0 , dataIndex ) ;
}
Material material = Material . matchMaterial ( raw ) ;
if ( material = = null )
throw new CommandException ( ) ;
npc . data ( ) . setPersistent ( NPC . MINECART_ITEM_METADATA , material . name ( ) ) ;
npc . data ( ) . setPersistent ( NPC . MINECART_ITEM_DATA_METADATA , data ) ;
}
if ( args . hasValueFlag ( " offset " ) ) {
npc . data ( ) . setPersistent ( NPC . MINECART_OFFSET_METADATA , args . getFlagInteger ( " offset " ) ) ;
}
Messaging . sendTr ( sender , Messages . MINECART_SET , npc . data ( ) . get ( NPC . MINECART_ITEM_METADATA , " " ) ,
npc . data ( ) . get ( NPC . MINECART_ITEM_DATA_METADATA , 0 ) , npc . data ( ) . get ( NPC . MINECART_OFFSET_METADATA , 0 ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " mount (--onnpc <npc id>) (-c (ancel)) " , desc = " Mounts a controllable NPC " , modifiers = {
" mount " } , min = 1 , max = 1 , flags = " c " , permission = " citizens.npc.mount " )
2018-03-19 08:02:07 +01:00
public void mount ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
2017-12-30 08:36:36 +01:00
if ( args . hasValueFlag ( " onnpc " ) ) {
NPC mount ;
try {
UUID uuid = UUID . fromString ( args . getFlag ( " onnpc " ) ) ;
mount = CitizensAPI . getNPCRegistry ( ) . getByUniqueId ( uuid ) ;
} catch ( IllegalArgumentException ex ) {
mount = CitizensAPI . getNPCRegistry ( ) . getById ( args . getFlagInteger ( " onnpc " ) ) ;
}
if ( mount = = null | | ! mount . isSpawned ( ) ) {
throw new CommandException ( Messaging . tr ( Messages . MOUNT_NPC_MUST_BE_SPAWNED , args . getFlag ( " onnpc " ) ) ) ;
}
if ( mount . equals ( npc ) ) {
throw new CommandException ( ) ;
}
NMS . mount ( mount . getEntity ( ) , npc . getEntity ( ) ) ;
return ;
2019-03-01 13:50:44 +01:00
} else if ( args . hasFlag ( 'c' ) ) {
npc . getTrait ( MountTrait . class ) . unmount ( ) ;
return ;
2017-12-30 08:36:36 +01:00
}
boolean enabled = npc . hasTrait ( Controllable . class ) & & npc . getTrait ( Controllable . class ) . isEnabled ( ) ;
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 ;
}
2018-03-19 08:02:07 +01:00
if ( ! ( sender instanceof Player ) ) {
throw new CommandException ( CommandMessages . MUST_BE_INGAME ) ;
}
Player player = ( Player ) sender ;
2017-12-30 08:36:36 +01:00
boolean success = npc . getTrait ( Controllable . class ) . mount ( player ) ;
if ( ! success ) {
Messaging . sendTr ( player , Messages . FAILED_TO_MOUNT_NPC , npc . getName ( ) ) ;
}
}
2020-01-17 10:11:23 +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 , permission = " citizens.npc.moveto " )
2017-12-30 08:36:36 +01:00
public void moveto ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
// Spawn the NPC if it isn't spawned to prevent NPEs
if ( ! npc . isSpawned ( ) ) {
2018-08-08 10:08:38 +02:00
npc . spawn ( npc . getTrait ( CurrentLocation . class ) . getLocation ( ) , SpawnReason . COMMAND ) ;
2017-12-30 08:36:36 +01:00
}
if ( ! npc . isSpawned ( ) ) {
throw new CommandException ( " NPC could not be spawned. " ) ;
}
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 ( ) ;
if ( args . hasValueFlag ( " x " ) )
to . setX ( args . getFlagDouble ( " x " ) ) ;
if ( args . hasValueFlag ( " y " ) )
to . setY ( args . getFlagDouble ( " y " ) ) ;
if ( args . hasValueFlag ( " z " ) )
to . setZ ( args . getFlagDouble ( " z " ) ) ;
if ( args . hasValueFlag ( " yaw " ) )
to . setYaw ( ( float ) args . getFlagDouble ( " yaw " ) ) ;
if ( args . hasValueFlag ( " pitch " ) )
to . setPitch ( ( float ) args . getFlagDouble ( " pitch " ) ) ;
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 ( ) ) ;
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , Messages . MOVETO_TELEPORTED , npc . getName ( ) , to ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , modifiers = {
" name " } , usage = " name " , desc = " Toggle nameplate visibility " , min = 1 , max = 1 , flags = " h " , permission = " citizens.npc.name " )
2017-12-30 08:36:36 +01:00
@Requirements ( selected = true , ownership = true , livingEntity = true )
public void name ( CommandContext args , CommandSender sender , NPC npc ) {
2020-01-17 10:11:23 +01:00
String old = npc . data ( ) . < Object > get ( NPC . NAMEPLATE_VISIBLE_METADATA , 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 ) ;
}
npc . data ( ) . setPersistent ( NPC . NAMEPLATE_VISIBLE_METADATA , old ) ;
Messaging . sendTr ( sender , Messages . NAMEPLATE_VISIBILITY_TOGGLED ) ;
}
@Command ( aliases = { " npc " } , desc = " Show basic NPC information " , max = 0 , permission = " citizens.npc.info " )
public void npc ( CommandContext args , CommandSender sender , final NPC npc ) {
Messaging . send ( sender , StringHelper . wrapHeader ( npc . getName ( ) ) ) ;
Messaging . send ( sender , " <a>ID: <e> " + npc . getId ( ) ) ;
Messaging . send ( sender , " <a>Type: <e> " + npc . getTrait ( MobType . class ) . getType ( ) ) ;
if ( npc . isSpawned ( ) ) {
Location loc = npc . getEntity ( ) . getLocation ( ) ;
String format = " <a>Spawned at <e>%d, %d, %d <a>in world<e> %s " ;
Messaging . send ( sender ,
String . format ( format , loc . getBlockX ( ) , loc . getBlockY ( ) , loc . getBlockZ ( ) , loc . getWorld ( ) . getName ( ) ) ) ;
}
Messaging . send ( sender , " <a>Traits<e> " ) ;
for ( Trait trait : npc . getTraits ( ) ) {
if ( CitizensAPI . getTraitFactory ( ) . isInternalTrait ( trait ) )
continue ;
String message = " <e>- <a> " + trait . getName ( ) ;
Messaging . send ( sender , message ) ;
}
}
2020-01-17 10:11:23 +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 } )
public void ocelot ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
OcelotModifiers trait = npc . getTrait ( OcelotModifiers . class ) ;
if ( args . hasFlag ( 's' ) ) {
trait . setSitting ( true ) ;
} else if ( args . hasFlag ( 'n' ) ) {
trait . setSitting ( false ) ;
}
if ( args . hasValueFlag ( " type " ) ) {
Ocelot . Type type = Util . matchEnum ( Ocelot . Type . values ( ) , args . getFlag ( " type " ) ) ;
if ( type = = null ) {
String valid = Util . listValuesPretty ( Ocelot . Type . values ( ) ) ;
throw new CommandException ( Messages . INVALID_OCELOT_TYPE , valid ) ;
}
trait . setType ( type ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " owner [name] " , 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 {
Owner ownerTrait = npc . getTrait ( Owner . class ) ;
if ( args . argsLength ( ) = = 1 ) {
Messaging . sendTr ( sender , Messages . NPC_OWNER , npc . getName ( ) , ownerTrait . getOwner ( ) ) ;
return ;
}
String name = args . getString ( 1 ) ;
if ( ownerTrait . isOwnedBy ( name ) )
throw new CommandException ( Messages . ALREADY_OWNER , name , npc . getName ( ) ) ;
ownerTrait . setOwner ( name ) ;
boolean serverOwner = name . equalsIgnoreCase ( Owner . SERVER ) ;
Messaging . sendTr ( sender , serverOwner ? Messages . OWNER_SET_SERVER : Messages . OWNER_SET , npc . getName ( ) , name ) ;
}
2020-01-17 10:11:23 +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 " )
2017-12-30 08:36:36 +01:00
public void passive ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
boolean passive = args . hasValueFlag ( " set " ) ? Boolean . parseBoolean ( args . getFlag ( " set " ) )
: npc . data ( ) . get ( NPC . DAMAGE_OTHERS_METADATA , true ) ;
npc . data ( ) . setPersistent ( NPC . DAMAGE_OTHERS_METADATA , ! passive ) ;
Messaging . sendTr ( sender , passive ? Messages . PASSIVE_SET : Messages . PASSIVE_UNSET , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " pathopt --avoid-water|aw [true|false] --stationary-ticks [ticks] --attack-range [range] --distance-margin [margin] --path-distance-margin [margin] " , desc = " Sets an NPC's pathfinding options " , modifiers = {
" pathopt " , " po " , " patho " } , min = 1 , max = 1 , permission = " citizens.npc.pathfindingoptions " )
2017-12-30 08:36:36 +01:00
public void pathfindingOptions ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
boolean found = false ;
if ( args . hasValueFlag ( " avoid-water " ) | | args . hasValueFlag ( " aw " ) ) {
String raw = args . getFlag ( " avoid-water " , args . getFlag ( " aw " ) ) ;
boolean avoid = Boolean . parseBoolean ( raw ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . avoidWater ( avoid ) ;
Messaging . sendTr ( sender , avoid ? Messages . PATHFINDING_OPTIONS_AVOID_WATER_SET
: Messages . PATHFINDING_OPTIONS_AVOID_WATER_UNSET , npc . getName ( ) ) ;
found = true ;
}
if ( args . hasValueFlag ( " stationary-ticks " ) ) {
int ticks = Integer . parseInt ( args . getFlag ( " stationary-ticks " ) ) ;
if ( ticks < 0 )
throw new CommandException ( ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . stationaryTicks ( ticks ) ;
Messaging . sendTr ( sender , Messages . PATHFINDING_OPTIONS_STATIONARY_TICKS_SET , npc . getName ( ) , ticks ) ;
found = true ;
}
if ( args . hasValueFlag ( " distance-margin " ) ) {
double distance = Double . parseDouble ( args . getFlag ( " distance-margin " ) ) ;
if ( distance < 0 )
throw new CommandException ( ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . distanceMargin ( Math . pow ( distance , 2 ) ) ;
Messaging . sendTr ( sender , Messages . PATHFINDING_OPTIONS_DISTANCE_MARGIN_SET , npc . getName ( ) , distance ) ;
found = true ;
}
2019-04-26 12:10:23 +02:00
if ( args . hasValueFlag ( " path-distance-margin " ) ) {
2019-04-27 12:31:16 +02:00
double distance = Double . parseDouble ( args . getFlag ( " path-distance-margin " ) ) ;
2019-04-26 12:10:23 +02:00
if ( distance < 0 )
throw new CommandException ( ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . pathDistanceMargin ( Math . pow ( distance , 2 ) ) ;
Messaging . sendTr ( sender , Messages . PATHFINDING_OPTIONS_PATH_DISTANCE_MARGIN_SET , npc . getName ( ) , distance ) ;
found = true ;
}
2017-12-30 08:36:36 +01:00
if ( args . hasValueFlag ( " attack-range " ) ) {
double range = Double . parseDouble ( args . getFlag ( " attack-range " ) ) ;
if ( range < 0 )
throw new CommandException ( ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . attackRange ( range ) ;
Messaging . sendTr ( sender , Messages . PATHFINDING_OPTIONS_ATTACK_RANGE_SET , npc . getName ( ) , range ) ;
found = true ;
}
if ( ! found ) {
throw new CommandException ( ) ;
}
}
2020-01-17 10:11:23 +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-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " playerlist (-a,r) " , 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 ) {
boolean remove = ! npc . data ( ) . get ( " removefromplayerlist " , Setting . REMOVE_PLAYERS_FROM_PLAYER_LIST . asBoolean ( ) ) ;
if ( args . hasFlag ( 'a' ) ) {
remove = false ;
} else if ( args . hasFlag ( 'r' ) ) {
remove = true ;
}
npc . data ( ) . setPersistent ( " removefromplayerlist " , remove ) ;
if ( npc . isSpawned ( ) ) {
npc . despawn ( DespawnReason . PENDING_RESPAWN ) ;
2018-08-08 10:08:38 +02:00
npc . spawn ( npc . getTrait ( 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 ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " pose (--save [name]|--assume [name]|--remove [name]) (-a) " , desc = " Changes/Saves/Lists NPC's head pose(s) " , flags = " a " , modifiers = {
" pose " } , min = 1 , max = 2 , permission = " citizens.npc.pose " )
2017-12-30 08:36:36 +01:00
public void pose ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
Poses trait = npc . getTrait ( Poses . class ) ;
if ( args . hasValueFlag ( " save " ) ) {
if ( args . getFlag ( " save " ) . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_POSE_NAME ) ;
if ( args . getSenderLocation ( ) = = null )
throw new ServerCommandException ( ) ;
if ( trait . addPose ( args . getFlag ( " save " ) , args . getSenderLocation ( ) ) ) {
Messaging . sendTr ( sender , Messages . POSE_ADDED ) ;
} else
throw new CommandException ( Messages . POSE_ALREADY_EXISTS , args . getFlag ( " save " ) ) ;
} else if ( args . hasValueFlag ( " assume " ) ) {
String pose = args . getFlag ( " assume " ) ;
if ( pose . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_POSE_NAME ) ;
if ( ! trait . hasPose ( pose ) )
throw new CommandException ( Messages . POSE_MISSING , pose ) ;
trait . assumePose ( pose ) ;
} else if ( args . hasValueFlag ( " remove " ) ) {
if ( args . getFlag ( " remove " ) . isEmpty ( ) )
throw new CommandException ( Messages . INVALID_POSE_NAME ) ;
if ( trait . removePose ( args . getFlag ( " remove " ) ) ) {
Messaging . sendTr ( sender , Messages . POSE_REMOVED ) ;
} else
throw new CommandException ( Messages . POSE_MISSING , args . getFlag ( " remove " ) ) ;
} else if ( ! args . hasFlag ( 'a' ) ) {
trait . describe ( sender , args . getInteger ( 1 , 1 ) ) ;
}
// Assume Player's pose
if ( ! args . hasFlag ( 'a' ) )
return ;
if ( args . getSenderLocation ( ) = = null )
throw new ServerCommandException ( ) ;
Location location = args . getSenderLocation ( ) ;
trait . assumePose ( location ) ;
}
2020-01-17 10:11:23 +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 ,
npc . getTrait ( Powered . class ) . toggle ( ) ? Messages . POWERED_SET : Messages . POWERED_STOPPED ) ;
}
2020-01-17 10:11:23 +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 )
2017-12-30 08:36:36 +01:00
public void profession ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
2018-07-19 14:18:47 +02:00
EntityType type = npc . getTrait ( MobType . class ) . getType ( ) ;
if ( type ! = EntityType . VILLAGER & & ! type . name ( ) . equals ( " ZOMBIE_VILLAGER " ) ) {
throw new RequirementMissingException ( Messaging . tr ( CommandMessages . REQUIREMENTS_INVALID_MOB_TYPE ,
type . name ( ) . toLowerCase ( ) . replace ( '_' , ' ' ) ) ) ;
}
2017-12-30 08:36:36 +01:00
String profession = args . getString ( 1 ) ;
Profession parsed = Util . matchEnum ( Profession . values ( ) , profession . toUpperCase ( ) ) ;
if ( parsed = = null ) {
throw new CommandException ( Messages . INVALID_PROFESSION , args . getString ( 1 ) ,
2019-04-24 15:01:22 +02:00
Joiner . on ( ',' ) . join ( Profession . values ( ) ) ) ;
2017-12-30 08:36:36 +01:00
}
npc . getTrait ( VillagerProfession . class ) . setProfession ( parsed ) ;
Messaging . sendTr ( sender , Messages . PROFESSION_SET , npc . getName ( ) , profession ) ;
}
2020-01-17 10:11:23 +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 } )
public void rabbitType ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
Rabbit . Type type ;
try {
type = Rabbit . Type . valueOf ( args . getString ( 1 ) . toUpperCase ( ) ) ;
} catch ( IllegalArgumentException ex ) {
2019-04-24 15:01:22 +02:00
throw new CommandException ( Messages . INVALID_RABBIT_TYPE , Joiner . on ( ',' ) . join ( Rabbit . Type . values ( ) ) ) ;
2017-12-30 08:36:36 +01:00
}
npc . getTrait ( RabbitType . class ) . setType ( type ) ;
Messaging . sendTr ( sender , Messages . RABBIT_TYPE_SET , npc . getName ( ) , type . name ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " remove|rem (all|id|name|--owner [owner]) " , desc = " Remove a NPC " , modifiers = { " remove " ,
" rem " } , min = 1 , max = 2 )
2017-12-30 08:36:36 +01:00
@Requirements
public void remove ( final CommandContext args , final CommandSender sender , NPC npc ) throws CommandException {
if ( args . hasValueFlag ( " owner " ) ) {
String owner = args . getFlag ( " owner " ) ;
2019-01-18 17:18:43 +01:00
Collection < NPC > npcs = Lists . newArrayList ( CitizensAPI . getNPCRegistry ( ) ) ;
2017-12-30 08:36:36 +01:00
for ( NPC o : npcs ) {
if ( o . getTrait ( Owner . class ) . isOwnedBy ( owner ) ) {
o . destroy ( ) ;
}
}
Messaging . sendTr ( sender , Messages . NPCS_REMOVED ) ;
return ;
}
if ( args . argsLength ( ) = = 2 ) {
if ( args . getString ( 1 ) . equalsIgnoreCase ( " all " ) ) {
if ( ! sender . hasPermission ( " citizens.admin.remove.all " ) & & ! sender . hasPermission ( " citizens.admin " ) )
throw new NoPermissionsException ( ) ;
2019-01-18 17:18:43 +01:00
CitizensAPI . getNPCRegistry ( ) . deregisterAll ( ) ;
2017-12-30 08:36:36 +01:00
Messaging . sendTr ( sender , Messages . REMOVED_ALL_NPCS ) ;
return ;
} else {
NPCCommandSelector . Callback callback = new NPCCommandSelector . Callback ( ) {
@Override
public void run ( NPC npc ) throws CommandException {
if ( npc = = null )
throw new CommandException ( Messages . COMMAND_MUST_HAVE_SELECTED ) ;
if ( ! ( sender instanceof ConsoleCommandSender ) & & ! npc . getTrait ( Owner . class ) . isOwnedBy ( sender ) )
throw new CommandException ( Messages . COMMAND_MUST_BE_OWNER ) ;
if ( ! sender . hasPermission ( " citizens.npc.remove " ) & & ! sender . hasPermission ( " citizens.admin " ) )
throw new NoPermissionsException ( ) ;
npc . destroy ( ) ;
Messaging . sendTr ( sender , Messages . NPC_REMOVED , npc . getName ( ) ) ;
}
} ;
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
return ;
}
}
if ( npc = = null )
throw new CommandException ( Messages . COMMAND_MUST_HAVE_SELECTED ) ;
if ( ! ( sender instanceof ConsoleCommandSender ) & & ! npc . getTrait ( Owner . class ) . isOwnedBy ( sender ) )
throw new CommandException ( Messages . COMMAND_MUST_BE_OWNER ) ;
if ( ! sender . hasPermission ( " citizens.npc.remove " ) & & ! sender . hasPermission ( " citizens.admin " ) )
throw new NoPermissionsException ( ) ;
npc . destroy ( ) ;
Messaging . sendTr ( sender , Messages . NPC_REMOVED , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +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 ( ) ;
String newName = Colorizer . parseColors ( args . getJoinedStrings ( 1 ) ) ;
int nameLength = npc . getTrait ( MobType . class ) . getType ( ) = = EntityType . PLAYER ? 46 : 64 ;
if ( newName . length ( ) > nameLength ) {
Messaging . sendErrorTr ( sender , Messages . NPC_NAME_TOO_LONG ) ;
newName = newName . substring ( 0 , nameLength ) ;
}
Location prev = npc . isSpawned ( ) ? npc . getEntity ( ) . getLocation ( ) : null ;
npc . despawn ( DespawnReason . PENDING_RESPAWN ) ;
npc . setName ( newName ) ;
if ( prev ! = null ) {
2018-08-08 10:08:38 +02:00
npc . spawn ( prev , SpawnReason . RESPAWN ) ;
2017-12-30 08:36:36 +01:00
}
Messaging . sendTr ( sender , Messages . NPC_RENAMED , oldName , newName ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " respawn [delay in ticks] " , desc = " Sets an NPC's respawn delay in ticks " , modifiers = {
" respawn " } , min = 1 , max = 2 , permission = " citizens.npc.respawn " )
2017-12-30 08:36:36 +01:00
public void respawn ( CommandContext args , CommandSender sender , NPC npc ) {
if ( args . argsLength ( ) > 1 ) {
int delay = args . getInteger ( 1 ) ;
npc . data ( ) . setPersistent ( NPC . RESPAWN_DELAY_METADATA , delay ) ;
Messaging . sendTr ( sender , Messages . RESPAWN_DELAY_SET , delay ) ;
} else {
Messaging . sendTr ( sender , Messages . RESPAWN_DELAY_DESCRIBE , npc . data ( ) . get ( NPC . RESPAWN_DELAY_METADATA , - 1 ) ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " scoreboard --addtag [tags] --removetag [tags] " , desc = " Controls an NPC's scoreboard " , modifiers = {
" scoreboard " } , min = 1 , max = 1 , permission = " citizens.npc.scoreboard " )
2019-07-12 09:39:38 +02:00
public void scoreboard ( CommandContext args , CommandSender sender , NPC npc ) {
ScoreboardTrait trait = npc . getTrait ( ScoreboardTrait . class ) ;
String output = " " ;
if ( args . hasValueFlag ( " addtag " ) ) {
for ( String tag : args . getFlag ( " addtag " ) . split ( " , " ) ) {
trait . addTag ( tag ) ;
}
output + = " " + Messaging . tr ( Messages . ADDED_SCOREBOARD_TAGS , args . getFlag ( " addtag " ) ) ;
}
if ( args . hasValueFlag ( " removetag " ) ) {
for ( String tag : args . getFlag ( " removetag " ) . split ( " , " ) ) {
trait . removeTag ( tag ) ;
}
output + = " " + Messaging . tr ( Messages . REMOVED_SCOREBOARD_TAGS , args . getFlag ( " removetag " ) ) ;
}
if ( ! output . isEmpty ( ) ) {
Messaging . send ( sender , output . trim ( ) ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " script --add [files] --remove [files] " , desc = " Controls an NPC's scripts " , modifiers = {
" script " } , min = 1 , max = 1 , permission = " citizens.npc.script " )
2017-12-30 08:36:36 +01:00
public void script ( CommandContext args , CommandSender sender , NPC npc ) {
ScriptTrait trait = npc . getTrait ( ScriptTrait . class ) ;
if ( args . hasValueFlag ( " add " ) ) {
List < String > files = new ArrayList < String > ( ) ;
for ( String file : args . getFlag ( " add " ) . split ( " , " ) ) {
if ( ! trait . validateFile ( file ) ) {
Messaging . sendErrorTr ( sender , Messages . INVALID_SCRIPT_FILE , file ) ;
return ;
}
files . add ( file ) ;
}
trait . addScripts ( files ) ;
}
if ( args . hasValueFlag ( " remove " ) ) {
trait . removeScripts ( Arrays . asList ( args . getFlag ( " remove " ) . split ( " , " ) ) ) ;
}
Messaging . sendTr ( sender , Messages . CURRENT_SCRIPTS , npc . getName ( ) , Joiner . on ( " ]],[[ " ) . join ( trait . getScripts ( ) ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " select|sel [id|name] (--r range) " , 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
public void select ( CommandContext args , final CommandSender sender , final NPC npc ) throws CommandException {
NPCCommandSelector . Callback callback = new NPCCommandSelector . Callback ( ) {
@Override
public void run ( NPC toSelect ) throws CommandException {
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 ) ;
}
} ;
if ( args . argsLength ( ) < = 1 ) {
if ( ! ( sender instanceof Player ) )
throw new ServerCommandException ( ) ;
double range = Math . abs ( args . getFlagDouble ( " r " , 10 ) ) ;
Entity player = ( Player ) sender ;
final Location location = args . getSenderLocation ( ) ;
List < Entity > search = player . getNearbyEntities ( range , range , range ) ;
Collections . sort ( search , new Comparator < Entity > ( ) {
@Override
public int compare ( Entity o1 , Entity o2 ) {
double d = o1 . getLocation ( ) . distanceSquared ( location ) - o2 . getLocation ( ) . distanceSquared ( location ) ;
return d > 0 ? 1 : d < 0 ? - 1 : 0 ;
}
} ) ;
for ( Entity possibleNPC : search ) {
2019-01-18 17:18:43 +01:00
NPC test = CitizensAPI . getNPCRegistry ( ) . getNPC ( possibleNPC ) ;
2017-12-30 08:36:36 +01:00
if ( test = = null )
continue ;
callback . run ( test ) ;
break ;
}
} else {
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
}
}
2020-01-17 10:11:23 +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 } )
public void sheep ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
SheepTrait trait = npc . getTrait ( SheepTrait . class ) ;
boolean hasArg = false ;
if ( args . hasValueFlag ( " sheared " ) ) {
trait . setSheared ( Boolean . valueOf ( args . getFlag ( " sheared " ) ) ) ;
hasArg = true ;
}
if ( args . hasValueFlag ( " color " ) ) {
DyeColor color = Util . matchEnum ( DyeColor . values ( ) , args . getFlag ( " 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 ;
}
if ( ! hasArg ) {
throw new CommandException ( ) ;
}
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " skin (-c -l(atest)) [name] (or -t [uuid/name] [data] [signature]) " , 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 , flags = " ctl " , permission = " citizens.npc.skin " )
2017-12-30 08:36:36 +01:00
@Requirements ( types = EntityType . PLAYER , selected = true , ownership = true )
public void skin ( final CommandContext args , final CommandSender sender , final NPC npc ) throws CommandException {
String skinName = npc . getName ( ) ;
if ( args . hasFlag ( 'c' ) ) {
npc . data ( ) . remove ( NPC . PLAYER_SKIN_UUID_METADATA ) ;
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 ) ;
SkinnableEntity skinnable = npc . getEntity ( ) instanceof SkinnableEntity ? ( SkinnableEntity ) npc . getEntity ( )
: null ;
if ( skinnable = = null ) {
throw new CommandException ( " Must be spawned. " ) ;
}
2018-06-27 06:00:03 +02:00
skinnable . 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 ;
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 ) ;
2017-12-30 08:36:36 +01:00
npc . data ( ) . setPersistent ( NPC . PLAYER_SKIN_UUID_METADATA , args . getString ( 1 ) ) ;
2018-03-09 15:15:26 +01:00
if ( args . hasFlag ( 'l' ) ) {
npc . data ( ) . setPersistent ( NPC . PLAYER_SKIN_USE_LATEST , true ) ;
2017-12-30 08:36:36 +01:00
}
skinName = args . getString ( 1 ) ;
}
Messaging . sendTr ( sender , Messages . SKIN_SET , npc . getName ( ) , skinName ) ;
if ( npc . isSpawned ( ) ) {
SkinnableEntity skinnable = npc . getEntity ( ) instanceof SkinnableEntity ? ( SkinnableEntity ) npc . getEntity ( )
: null ;
if ( skinnable ! = null ) {
skinnable . setSkinName ( skinName , true ) ;
}
}
}
2020-01-17 10:11:23 +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 )
public void skinLayers ( final CommandContext args , final CommandSender sender , final NPC npc )
throws CommandException {
SkinLayers trait = npc . getTrait ( SkinLayers . class ) ;
if ( args . hasValueFlag ( " cape " ) ) {
trait . setVisible ( Layer . CAPE , Boolean . valueOf ( args . getFlag ( " cape " ) ) ) ;
}
if ( args . hasValueFlag ( " hat " ) ) {
trait . setVisible ( Layer . HAT , Boolean . valueOf ( args . getFlag ( " hat " ) ) ) ;
}
if ( args . hasValueFlag ( " jacket " ) ) {
trait . setVisible ( Layer . JACKET , Boolean . valueOf ( args . getFlag ( " jacket " ) ) ) ;
}
if ( args . hasValueFlag ( " sleeves " ) ) {
boolean hasSleeves = Boolean . valueOf ( args . getFlag ( " sleeves " ) ) ;
trait . setVisible ( Layer . LEFT_SLEEVE , hasSleeves ) ;
trait . setVisible ( Layer . RIGHT_SLEEVE , hasSleeves ) ;
}
if ( args . hasValueFlag ( " pants " ) ) {
boolean hasPants = Boolean . valueOf ( args . getFlag ( " pants " ) ) ;
trait . setVisible ( Layer . LEFT_PANTS , hasPants ) ;
trait . setVisible ( Layer . RIGHT_PANTS , hasPants ) ;
}
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-01-17 10:11:23 +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 ) {
SlimeSize trait = npc . getTrait ( SlimeSize . class ) ;
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-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " sound (--death [death sound|d]) (--ambient [ambient sound|d]) (--hurt [hurt sound|d]) (-n(one)) (-d(efault)) " , desc = " Sets an NPC's played sounds " , modifiers = {
" sound " } , flags = " dns " , min = 1 , max = 1 , permission = " citizens.npc.sound " )
2017-12-30 08:36:36 +01:00
@Requirements ( selected = true , ownership = true , livingEntity = true , excludedTypes = { EntityType . PLAYER } )
public void sound ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
String ambientSound = npc . data ( ) . get ( NPC . AMBIENT_SOUND_METADATA ) ;
String deathSound = npc . data ( ) . get ( NPC . DEATH_SOUND_METADATA ) ;
String hurtSound = npc . data ( ) . get ( NPC . HURT_SOUND_METADATA ) ;
if ( args . getValueFlags ( ) . size ( ) = = 0 & & args . getFlags ( ) . size ( ) = = 0 ) {
Messaging . sendTr ( sender , Messages . SOUND_INFO , npc . getName ( ) , ambientSound , hurtSound , deathSound ) ;
return ;
}
if ( args . hasFlag ( 'n' ) | | args . hasFlag ( 's' ) ) {
ambientSound = deathSound = hurtSound = " " ;
npc . data ( ) . setPersistent ( NPC . SILENT_METADATA , true ) ;
}
if ( args . hasFlag ( 'd' ) ) {
ambientSound = deathSound = hurtSound = null ;
} else {
if ( args . hasValueFlag ( " death " ) ) {
deathSound = args . getFlag ( " death " ) . equals ( " d " ) ? null : NMS . getSound ( args . getFlag ( " death " ) ) ;
}
if ( args . hasValueFlag ( " ambient " ) ) {
ambientSound = args . getFlag ( " ambient " ) . equals ( " d " ) ? null : NMS . getSound ( args . getFlag ( " ambient " ) ) ;
}
if ( args . hasValueFlag ( " hurt " ) ) {
hurtSound = args . getFlag ( " hurt " ) . equals ( " d " ) ? null : NMS . getSound ( args . getFlag ( " hurt " ) ) ;
}
}
if ( deathSound = = null ) {
npc . data ( ) . remove ( NPC . DEATH_SOUND_METADATA ) ;
} else {
npc . data ( ) . setPersistent ( NPC . DEATH_SOUND_METADATA , deathSound ) ;
}
if ( hurtSound = = null ) {
npc . data ( ) . remove ( NPC . HURT_SOUND_METADATA ) ;
} else {
npc . data ( ) . setPersistent ( NPC . HURT_SOUND_METADATA , hurtSound ) ;
}
if ( ambientSound = = null ) {
2019-07-23 13:38:20 +02:00
npc . data ( ) . remove ( NPC . AMBIENT_SOUND_METADATA ) ;
2017-12-30 08:36:36 +01:00
} else {
npc . data ( ) . setPersistent ( NPC . AMBIENT_SOUND_METADATA , ambientSound ) ;
}
if ( ambientSound ! = null & & ambientSound . isEmpty ( ) ) {
ambientSound = " none " ;
}
if ( hurtSound ! = null & & hurtSound . isEmpty ( ) ) {
hurtSound = " none " ;
}
if ( deathSound ! = null & & deathSound . isEmpty ( ) ) {
deathSound = " none " ;
}
2019-09-17 13:44:43 +02:00
if ( ( ! StringUtils . isNullOrEmpty ( ambientSound ) & & ! ambientSound . equals ( " none " ) )
| | ( ! StringUtils . isNullOrEmpty ( deathSound ) & & ! deathSound . equals ( " none " ) )
| | ( ! StringUtils . isNullOrEmpty ( hurtSound ) & & ! hurtSound . equals ( " none " ) ) ) {
2017-12-30 08:36:36 +01:00
npc . data ( ) . setPersistent ( NPC . SILENT_METADATA , false ) ;
}
Messaging . sendTr ( sender , Messages . SOUND_SET , npc . getName ( ) , ambientSound , hurtSound , deathSound ) ;
}
2020-01-17 10:11:23 +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 )
public void spawn ( final CommandContext args , final CommandSender sender , NPC npc ) throws CommandException {
NPCCommandSelector . Callback callback = new NPCCommandSelector . Callback ( ) {
@Override
public void run ( NPC respawn ) throws CommandException {
if ( respawn = = null ) {
if ( args . argsLength ( ) > 1 ) {
throw new CommandException ( Messages . NO_NPC_WITH_ID_FOUND , args . getString ( 1 ) ) ;
} else {
throw new CommandException ( CommandMessages . MUST_HAVE_SELECTED ) ;
}
}
if ( respawn . isSpawned ( ) ) {
throw new CommandException ( Messages . NPC_ALREADY_SPAWNED , respawn . getName ( ) ) ;
}
Location location = respawn . getTrait ( CurrentLocation . class ) . getLocation ( ) ;
if ( location = = null | | args . hasValueFlag ( " location " ) ) {
if ( args . getSenderLocation ( ) = = null )
throw new CommandException ( Messages . NO_STORED_SPAWN_LOCATION ) ;
location = args . getSenderLocation ( ) ;
}
if ( args . hasFlag ( 'l' ) & & ! Util . isLoaded ( location ) ) {
location . getChunk ( ) . load ( ) ;
}
2018-08-08 10:08:38 +02:00
if ( respawn . spawn ( location , SpawnReason . COMMAND ) ) {
2017-12-30 08:36:36 +01:00
selector . select ( sender , respawn ) ;
Messaging . sendTr ( sender , Messages . NPC_SPAWNED , respawn . getName ( ) ) ;
}
}
} ;
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-01-17 10:11:23 +01:00
@Command ( aliases = {
" npc " } , usage = " speak message to speak --target npcid|player_name --type vocal_type " , desc = " Uses the NPCs SpeechController to talk " , modifiers = {
" speak " } , min = 2 , permission = " citizens.npc.speak " )
2017-12-30 08:36:36 +01:00
public void speak ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
String type = npc . getTrait ( Speech . class ) . getDefaultVocalChord ( ) ;
String message = Colorizer . parseColors ( args . getJoinedStrings ( 1 ) ) ;
if ( message . length ( ) < = 0 ) {
Messaging . send ( sender , " Default Vocal Chord for " + npc . getName ( ) + " : "
+ npc . getTrait ( Speech . class ) . getDefaultVocalChord ( ) ) ;
return ;
}
SpeechContext context = new SpeechContext ( message ) ;
if ( args . hasValueFlag ( " target " ) ) {
if ( args . getFlag ( " target " ) . matches ( " \\ d+ " ) ) {
NPC target = CitizensAPI . getNPCRegistry ( ) . getById ( Integer . valueOf ( args . getFlag ( " target " ) ) ) ;
if ( target ! = null )
context . addRecipient ( target . getEntity ( ) ) ;
} else {
2019-04-26 15:14:15 +02:00
Player player = Bukkit . getPlayerExact ( args . getFlag ( " target " ) ) ;
2017-12-30 08:36:36 +01:00
if ( player ! = null ) {
context . addRecipient ( ( Entity ) player ) ;
}
}
}
if ( args . hasValueFlag ( " type " ) ) {
if ( CitizensAPI . getSpeechFactory ( ) . isRegistered ( args . getFlag ( " type " ) ) )
type = args . getFlag ( " type " ) ;
}
npc . getDefaultSpeechController ( ) . speak ( context , type ) ;
}
2020-01-17 10:11:23 +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 ) ) ;
if ( newSpeed > = Setting . MAX_SPEED . asDouble ( ) )
throw new CommandException ( Messages . SPEED_MODIFIER_ABOVE_LIMIT ) ;
npc . getNavigator ( ) . getDefaultParameters ( ) . speedModifier ( newSpeed ) ;
Messaging . sendTr ( sender , Messages . SPEED_MODIFIER_SET , newSpeed ) ;
}
2020-01-17 10:11:23 +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 " )
2017-12-30 08:36:36 +01:00
public void swim ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
boolean swim = args . hasValueFlag ( " set " ) ? Boolean . parseBoolean ( args . getFlag ( " set " ) )
: ! npc . data ( ) . get ( NPC . SWIMMING_METADATA , true ) ;
npc . data ( ) . setPersistent ( NPC . SWIMMING_METADATA , swim ) ;
Messaging . sendTr ( sender , swim ? Messages . SWIMMING_SET : Messages . SWIMMING_UNSET , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " targetable " , desc = " Toggles an NPC's targetability " , modifiers = {
" targetable " } , min = 1 , max = 1 , permission = " citizens.npc.targetable " )
2017-12-30 08:36:36 +01:00
public void targetable ( CommandContext args , CommandSender sender , NPC npc ) {
boolean targetable = ! npc . data ( ) . get ( NPC . TARGETABLE_METADATA ,
npc . data ( ) . get ( NPC . DEFAULT_PROTECTED_METADATA , true ) ) ;
if ( args . hasFlag ( 't' ) ) {
npc . data ( ) . set ( NPC . TARGETABLE_METADATA , targetable ) ;
} else {
npc . data ( ) . setPersistent ( NPC . TARGETABLE_METADATA , targetable ) ;
}
Messaging . sendTr ( sender , targetable ? Messages . TARGETABLE_SET : Messages . TARGETABLE_UNSET , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " tp " , desc = " Teleport to a NPC " , modifiers = { " tp " ,
" teleport " } , min = 1 , max = 1 , permission = " citizens.npc.tp " )
2017-12-30 08:36:36 +01:00
public void tp ( CommandContext args , Player player , NPC npc ) {
Location to = npc . getTrait ( CurrentLocation . class ) . getLocation ( ) ;
if ( to = = null ) {
Messaging . sendError ( player , Messages . TELEPORT_NPC_LOCATION_NOT_FOUND ) ;
return ;
}
player . teleport ( to , TeleportCause . COMMAND ) ;
Messaging . sendTr ( player , Messages . TELEPORTED_TO_NPC , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " tphere " , desc = " Teleport a NPC to your location " , modifiers = { " tphere " ,
" tph " , " move " } , min = 1 , max = 1 , permission = " citizens.npc.tphere " )
2017-12-30 08:36:36 +01:00
public void tphere ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
if ( args . getSenderLocation ( ) = = null )
throw new ServerCommandException ( ) ;
// Spawn the NPC if it isn't spawned to prevent NPEs
if ( ! npc . isSpawned ( ) ) {
2018-08-08 10:08:38 +02:00
npc . spawn ( args . getSenderLocation ( ) , SpawnReason . COMMAND ) ;
2017-12-30 08:36:36 +01:00
if ( ! sender . hasPermission ( " citizens.npc.tphere.multiworld " )
& & npc . getEntity ( ) . getLocation ( ) . getWorld ( ) ! = args . getSenderLocation ( ) . getWorld ( ) ) {
npc . despawn ( DespawnReason . REMOVAL ) ;
throw new CommandException ( Messages . CANNOT_TELEPORT_ACROSS_WORLDS ) ;
}
} else {
if ( ! sender . hasPermission ( " citizens.npc.tphere.multiworld " )
& & npc . getEntity ( ) . getLocation ( ) . getWorld ( ) ! = args . getSenderLocation ( ) . getWorld ( ) ) {
npc . despawn ( DespawnReason . REMOVAL ) ;
throw new CommandException ( Messages . CANNOT_TELEPORT_ACROSS_WORLDS ) ;
}
npc . teleport ( args . getSenderLocation ( ) , TeleportCause . COMMAND ) ;
}
Messaging . sendTr ( sender , Messages . NPC_TELEPORTED , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +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 ) ;
}
2020-01-17 10:11:23 +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 " )
2017-12-30 08:36:36 +01:00
public void type ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
EntityType type = Util . matchEntityType ( args . getString ( 1 ) ) ;
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 ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " vulnerable (-t) " , 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 ) {
boolean vulnerable = ! npc . data ( ) . get ( NPC . DEFAULT_PROTECTED_METADATA , true ) ;
if ( args . hasFlag ( 't' ) ) {
npc . data ( ) . set ( NPC . DEFAULT_PROTECTED_METADATA , vulnerable ) ;
} else {
npc . data ( ) . setPersistent ( NPC . DEFAULT_PROTECTED_METADATA , vulnerable ) ;
}
String key = vulnerable ? Messages . VULNERABLE_STOPPED : Messages . VULNERABLE_SET ;
Messaging . sendTr ( sender , key , npc . getName ( ) ) ;
}
2020-01-17 10:11:23 +01:00
@Command ( aliases = { " npc " } , usage = " wither (--charged [charged]) " , 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 } )
public void wither ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
WitherTrait trait = npc . getTrait ( WitherTrait . class ) ;
if ( args . hasValueFlag ( " charged " ) ) {
trait . setCharged ( Boolean . valueOf ( args . getFlag ( " charged " ) ) ) ;
}
}
2020-01-17 10:11:23 +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 )
public void wolf ( CommandContext args , CommandSender sender , NPC npc ) throws CommandException {
WolfModifiers trait = npc . getTrait ( 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 ( ) ) ;
}
2017-12-30 08:36:36 +01:00
if ( args . hasValueFlag ( " collar " ) ) {
String unparsed = args . getFlag ( " collar " ) ;
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
}