Add some javadoc

This commit is contained in:
fullwall 2019-05-16 19:58:29 +08:00
parent 65cbb8850f
commit 8c30a785a4
36 changed files with 524 additions and 153 deletions

View File

@ -10,6 +10,11 @@ import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.util.Messages;
/**
* Persists the Minecraft age variable for {@link Ageable}s. Will also set baby for {@link Zombie}s.
*
* @see Ageable
*/
@TraitName("age")
public class Age extends Trait implements Toggleable {
@Persist
@ -22,6 +27,9 @@ public class Age extends Trait implements Toggleable {
super("age");
}
/**
* Send a brief description of the current state of the trait to the supplied {@link CommandSender}.
*/
public void describe(CommandSender sender) {
Messaging.sendTr(sender, Messages.AGE_TRAIT_DESCRIPTION, npc.getName(), age, locked);
}
@ -61,6 +69,9 @@ public class Age extends Trait implements Toggleable {
}
}
/**
* Toggles the age lock variable and returns whether the age is currently locked.
*/
@Override
public boolean toggle() {
locked = !locked;

View File

@ -16,6 +16,9 @@ import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.util.Anchor;
import net.citizensnpcs.util.Messages;
/**
* Persists a list of {@link Anchor}s.
*/
@TraitName("anchors")
public class Anchors extends Trait {
private final List<Anchor> anchors = new ArrayList<Anchor>();
@ -33,10 +36,12 @@ public class Anchors extends Trait {
}
@EventHandler
public void checkWorld(WorldLoadEvent event) {
for (Anchor anchor : anchors)
if (!anchor.isLoaded())
private void checkWorld(WorldLoadEvent event) {
for (Anchor anchor : anchors) {
if (!anchor.isLoaded()) {
anchor.load();
}
}
}
public Anchor getAnchor(String name) {

View File

@ -7,6 +7,9 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists data related to {@link ArmorStand} NPCs.
*/
@TraitName("armorstandtrait")
public class ArmorStandTrait extends Trait {
@Persist
@ -82,26 +85,44 @@ public class ArmorStandTrait extends Trait {
}
}
/**
* @see ArmorStand#setGravity(boolean)
*/
public void setGravity(boolean gravity) {
this.gravity = gravity;
}
/**
* @see ArmorStand#setArms(boolean)
*/
public void setHasArms(boolean arms) {
this.hasarms = arms;
}
/**
* @see ArmorStand#setBasePlate(boolean)
*/
public void setHasBaseplate(boolean baseplate) {
this.hasbaseplate = baseplate;
}
/**
* @see ArmorStand#setMarker(boolean)
*/
public void setMarker(boolean marker) {
this.marker = marker;
}
/**
* @see ArmorStand#setSmall(boolean)
*/
public void setSmall(boolean small) {
this.small = small;
}
/**
* @see ArmorStand#setVisible(boolean)
*/
public void setVisible(boolean visible) {
this.visible = visible;
}

View File

@ -31,6 +31,12 @@ import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
/**
* Persists the controllable status for /npc controllable
*
* A controllable {@link NPC} can be mounted by a {@link Player} using right click or /npc mount and moved around using
* e.g. arrow keys.
*/
@TraitName("controllable")
public class Controllable extends Trait implements Toggleable, CommandConfigurable {
private MovementController controller = new GroundController();
@ -49,6 +55,11 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
this.enabled = enabled;
}
/**
* Configures the explicit type parameter.
*
* @see #setExplicitType(EntityType)
*/
@Override
public void configure(CommandContext args) {
if (args.hasFlag('f')) {
@ -103,22 +114,14 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
controller = new LookAirController();
return;
}
Class<? extends MovementController> clazz = controllerTypes.get(type);
if (clazz == null) {
Constructor<? extends MovementController> innerConstructor = CONTROLLER_TYPES.get(type);
if (innerConstructor == null) {
controller = new GroundController();
return;
}
Constructor<? extends MovementController> innerConstructor = null;
try {
innerConstructor = clazz.getConstructor(Controllable.class);
innerConstructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
try {
if (innerConstructor == null) {
controller = clazz.newInstance();
if (innerConstructor.getParameterCount() == 0) {
controller = innerConstructor.newInstance();
} else {
controller = innerConstructor.newInstance(this);
}
@ -128,6 +131,13 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
}
}
/**
* Attempts to mount the {@link NPC} onto the supplied {@link Player}.
*
* @param toMount
* the player to mount
* @return whether the mount was successful
*/
public boolean mount(Player toMount) {
boolean found = NMS.getPassengers(npc.getEntity()).size() == 0;
for (Entity passenger : NMS.getPassengers(npc.getEntity())) {
@ -143,7 +153,7 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
public void onPlayerInteract(PlayerInteractEvent event) {
private void onPlayerInteract(PlayerInteractEvent event) {
if (!npc.isSpawned() || !enabled)
return;
Action performed = event.getAction();
@ -164,7 +174,7 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
}
@EventHandler
public void onRightClick(NPCRightClickEvent event) {
private void onRightClick(NPCRightClickEvent event) {
if (!enabled || !npc.isSpawned() || !event.getNPC().equals(npc))
return;
controller.rightClickEntity(event);
@ -199,6 +209,16 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
return enabled;
}
/**
* Configures the explicit typei.e. whether the NPC should be controlled as if it was a certain {@link EntityType}.
*
* @param type
* the explicit type
*/
public void setExplicitType(EntityType type) {
this.explicitType = type;
}
private void setMountedYaw(Entity entity) {
if (entity instanceof EnderDragon || !Setting.USE_BOAT_CONTROLS.asBoolean())
return; // EnderDragon handles this separately
@ -218,6 +238,12 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
NMS.look(entity, loc.getYaw(), loc.getPitch());
}
/**
* Sets whether the {@link Player} attempting to mount the {@link NPC} must actually own the {@link NPC} to mount
* it.
*
* @see Owner#isOwnedBy(org.bukkit.command.CommandSender)
*/
public void setOwnerRequired(boolean ownerRequired) {
this.ownerRequired = ownerRequired;
}
@ -378,19 +404,47 @@ public class Controllable extends Trait implements Toggleable, CommandConfigurab
}
}
/**
* Register a movement controller for a certain {@link EntityType} to be used for {@link NPC}s with that type.
*
* Default controllers are registered for BAT, BLAZE, ENDER_DRAGON, GHAST, WITHER and PARROT using
* {@link PlayerInputAirController}.
*
* @param type
* the entity type
* @param clazz
* the controller class
*/
public static void registerControllerType(EntityType type, Class<? extends MovementController> clazz) {
controllerTypes.put(type, clazz);
try {
Constructor<? extends MovementController> constructor = clazz.getConstructor(Controllable.class);
constructor.setAccessible(true);
CONTROLLER_TYPES.put(type, constructor);
return;
} catch (Exception e) {
try {
Constructor<? extends MovementController> constructor = clazz.getConstructor();
constructor.setAccessible(true);
CONTROLLER_TYPES.put(type, constructor);
} catch (Exception e2) {
throw new RuntimeException(e2);
}
}
}
private static final Map<EntityType, Class<? extends MovementController>> controllerTypes = Maps
private static final Map<EntityType, Constructor<? extends MovementController>> CONTROLLER_TYPES = Maps
.newEnumMap(EntityType.class);
static {
controllerTypes.put(EntityType.BAT, PlayerInputAirController.class);
controllerTypes.put(EntityType.BLAZE, PlayerInputAirController.class);
controllerTypes.put(EntityType.ENDER_DRAGON, PlayerInputAirController.class);
controllerTypes.put(EntityType.GHAST, PlayerInputAirController.class);
controllerTypes.put(EntityType.WITHER, PlayerInputAirController.class);
controllerTypes.put(EntityType.UNKNOWN, LookAirController.class);
registerControllerType(EntityType.BAT, PlayerInputAirController.class);
registerControllerType(EntityType.BLAZE, PlayerInputAirController.class);
registerControllerType(EntityType.ENDER_DRAGON, PlayerInputAirController.class);
registerControllerType(EntityType.GHAST, PlayerInputAirController.class);
registerControllerType(EntityType.WITHER, PlayerInputAirController.class);
try {
registerControllerType(EntityType.valueOf("PARROT"), PlayerInputAirController.class);
} catch (IllegalArgumentException ex) {
}
registerControllerType(EntityType.UNKNOWN, LookAirController.class);
}
}

View File

@ -6,6 +6,9 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists the current {@link Location} of the {@link NPC}. Will cache last known location if despawned.
*/
@TraitName("location")
public class CurrentLocation extends Trait {
@Persist(value = "", required = true)

View File

@ -12,10 +12,13 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists a {@link Player} to follow while spawned. Optionally allows protecting of the player as well.
*/
@TraitName("followtrait")
public class FollowTrait extends Trait {
@Persist
private boolean active = false;
@Persist("active")
private boolean enabled = false;
@Persist
private UUID followingUUID;
private Player player;
@ -26,12 +29,19 @@ public class FollowTrait extends Trait {
super("followtrait");
}
private boolean isActive() {
return active && npc.isSpawned() && player != null && npc.getEntity().getWorld().equals(player.getWorld());
/**
* Returns whether the trait is actively following a {@link Player}.
*/
public boolean isActive() {
return enabled && npc.isSpawned() && player != null && npc.getEntity().getWorld().equals(player.getWorld());
}
public boolean isEnabled() {
return enabled;
}
@EventHandler
public void onEntityDamage(EntityDamageByEntityEvent event) {
private void onEntityDamage(EntityDamageByEntityEvent event) {
if (isActive() && event.getEntity().equals(player)) {
npc.getNavigator().setTarget(event.getDamager(), true);
}
@ -55,18 +65,29 @@ public class FollowTrait extends Trait {
}
}
/**
* Toggles and/or sets the {@link OfflinePlayer} to follow and whether to protect them (similar to wolves in
* Minecraft, attack whoever attacks the player).
*
* Will toggle if the {@link OfflinePlayer} is the player currently being followed.
*
* @param player
* the player to follow
* @param protect
* whether to protect the player
* @return whether the trait is enabled
*/
public boolean toggle(OfflinePlayer player, boolean protect) {
this.protect = protect;
if (player.getUniqueId().equals(this.followingUUID) || this.followingUUID == null) {
this.active = !active;
this.enabled = !enabled;
}
this.followingUUID = player.getUniqueId();
if (npc.getNavigator().isNavigating() && this.player != null
&& npc.getNavigator().getEntityTarget() != null
if (npc.getNavigator().isNavigating() && this.player != null && npc.getNavigator().getEntityTarget() != null
&& this.player == npc.getNavigator().getEntityTarget().getTarget()) {
npc.getNavigator().cancelNavigation();
}
this.player = null;
return this.active;
return this.enabled;
}
}

View File

@ -7,6 +7,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists the {@link GameMode} of a {@link Player} NPC.
*
* @see Player#setGameMode(GameMode)
*/
@TraitName("gamemodetrait")
public class GameModeTrait extends Trait {
@Persist

View File

@ -6,6 +6,9 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Enable/disable gravity. Without gravity the y velocity of the NPC is always set to <code>0</code>
*/
@TraitName("gravity")
public class Gravity extends Trait implements Toggleable {
@Persist
@ -15,6 +18,12 @@ public class Gravity extends Trait implements Toggleable {
super("gravity");
}
/**
* Set whether to disable gravity or not
*
* @param gravitate
* true = disable gravity, false = enable gravity
*/
public void gravitate(boolean gravitate) {
enabled = gravitate;
}

View File

@ -9,6 +9,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists various {@link Horse} metadata.
*
* @see Horse
*/
@TraitName("horsemodifiers")
public class HorseModifiers extends Trait {
@Persist("armor")
@ -30,6 +35,9 @@ public class HorseModifiers extends Trait {
return armor;
}
/**
* @see Horse#getColor()
*/
public Color getColor() {
return color;
}
@ -38,6 +46,9 @@ public class HorseModifiers extends Trait {
return saddle;
}
/**
* @see Horse#getStyle()
*/
public Style getStyle() {
return style;
}
@ -60,11 +71,17 @@ public class HorseModifiers extends Trait {
this.armor = armor;
}
/**
* @see Horse#setCarryingChest(boolean)
*/
public void setCarryingChest(boolean carryingChest) {
this.carryingChest = carryingChest;
updateModifiers();
}
/**
* @see Horse#setColor(Color)
*/
public void setColor(Horse.Color color) {
this.color = color;
updateModifiers();
@ -74,6 +91,9 @@ public class HorseModifiers extends Trait {
this.saddle = saddle;
}
/**
* @see Horse#setStyle(Style)
*/
public void setStyle(Horse.Style style) {
this.style = style;
updateModifiers();

View File

@ -25,6 +25,10 @@ import net.citizensnpcs.api.util.DataKey;
import net.citizensnpcs.util.NMS;
import net.citizensnpcs.util.Util;
/**
* Persists the /npc lookclose metadata
*
*/
@TraitName("lookclose")
public class LookClose extends Trait implements Toggleable, CommandConfigurable {
@Persist("enabled")
@ -47,10 +51,14 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
super("lookclose");
}
private boolean canSeeTarget() {
/**
* Returns whether the target can be seen. Will use realistic line of sight if {@link #setRealisticLooking(boolean)}
* is true.
*/
public boolean canSeeTarget() {
return realisticLooking && npc.getEntity() instanceof LivingEntity
? ((LivingEntity) npc.getEntity()).hasLineOfSight(lookingAt)
: true;
: lookingAt != null && lookingAt.isValid();
}
@Override
@ -59,7 +67,10 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
realisticLooking = args.hasFlag('r');
}
private void findNewTarget() {
/**
* Finds a new look-close target
*/
public void findNewTarget() {
List<Entity> nearby = npc.getEntity().getNearbyEntities(range, range, range);
Collections.sort(nearby, new Comparator<Entity>() {
@Override
@ -107,6 +118,9 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
range = key.getDouble("range");
}
/**
* Enables/disables the trait
*/
public void lookClose(boolean lookClose) {
enabled = lookClose;
}
@ -150,10 +164,16 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
key.setDouble("range", range);
}
/**
* Enables random looking - will look at a random {@link Location} every so often if enabled.
*/
public void setRandomLook(boolean enableRandomLook) {
this.enableRandomLook = enableRandomLook;
}
/**
* Sets the delay between random looking in ticks
*/
public void setRandomLookDelay(int delay) {
this.randomLookDelay = delay;
}
@ -166,10 +186,16 @@ public class LookClose extends Trait implements Toggleable, CommandConfigurable
this.randomYawRange = new float[] { min, max };
}
/**
* Sets the maximum range in blocks to look at other Entities
*/
public void setRange(int range) {
this.range = range;
}
/**
* Enables/disables realistic looking (using line of sight checks). More computationally expensive.
*/
public void setRealisticLooking(boolean realistic) {
this.realisticLooking = realistic;
}

View File

@ -12,6 +12,9 @@ import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.util.NMS;
/**
* Persists the NPC's mounted on entity, if any. Will attempt to respawn on mount.
*/
@TraitName("mounttrait")
public class MountTrait extends Trait {
private UUID mountedOn;

View File

@ -7,6 +7,11 @@ import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.util.NMS;
/**
* Persists Ocelot metadata.
*
* @see Ocelot
*/
@TraitName("ocelotmodifiers")
public class OcelotModifiers extends Trait {
@Persist("sitting")

View File

@ -19,6 +19,9 @@ import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Pose;
import net.citizensnpcs.util.Util;
/**
* Persists named {@link Pose}s.
*/
@TraitName("poses")
public class Poses extends Trait {
private final Map<String, Pose> poses = Maps.newHashMap();
@ -27,6 +30,11 @@ public class Poses extends Trait {
super("poses");
}
/**
* Add a {@link Pose}
*
* @return whether the pose has already been added
*/
public boolean addPose(String name, Location location) {
name = name.toLowerCase();
Pose newPose = new Pose(name, location.getPitch(), location.getYaw());
@ -43,10 +51,16 @@ public class Poses extends Trait {
Util.assumePose(npc.getEntity(), yaw, pitch);
}
/**
* Sets the yaw/pitch to the supplied {@link Location}.
*/
public void assumePose(Location location) {
assumePose(location.getYaw(), location.getPitch());
}
/**
* Sets the yaw/pitch to the stored pose, looked up by name.
*/
public void assumePose(String flag) {
Pose pose = poses.get(flag.toLowerCase());
assumePose(pose.getYaw(), pose.getPitch());

View File

@ -6,6 +6,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists {@link Creeper} powered status.
*
* @see Creeper#setPowered(boolean)
*/
@TraitName("powered")
public class Powered extends Trait implements Toggleable {
@Persist("")

View File

@ -6,6 +6,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists Rabbit metadata.
*
* @see Rabbit#getRabbitType()
*/
@TraitName("rabbittype")
public class RabbitType extends Trait {
private Rabbit rabbit;

View File

@ -9,6 +9,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists saddle metadata.
*
* @see Pig#hasSaddle()
*/
@TraitName("saddle")
public class Saddle extends Trait implements Toggleable {
private boolean pig;

View File

@ -13,11 +13,17 @@ import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.scripting.CompileCallback;
import net.citizensnpcs.api.scripting.Script;
import net.citizensnpcs.api.scripting.ScriptCompiler;
import net.citizensnpcs.api.scripting.ScriptFactory;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey;
/**
* Stores a list of scripts, which are pieces of arbitrary code that can be run every tick.
*
* @see ScriptCompiler
*/
@TraitName("scripttrait")
public class ScriptTrait extends Trait {
@Persist
@ -28,6 +34,11 @@ public class ScriptTrait extends Trait {
super("scripttrait");
}
/**
* Add and load all given script file names
*
* @see #loadScript(String)
*/
public void addScripts(List<String> scripts) {
for (String f : scripts) {
if (!files.contains(f) && validateFile(f)) {
@ -50,6 +61,13 @@ public class ScriptTrait extends Trait {
}
}
/**
* Compile and load a script given by the file name.
*
* @param file
* the script file name relative to the script folder
* @see Citizens#getScriptFolder()
*/
public void loadScript(final String file) {
File f = new File(JavaPlugin.getPlugin(Citizens.class).getScriptFolder(), file);
CitizensAPI.getScriptCompiler().compile(f).cache(true).withCallback(new CompileCallback() {
@ -73,6 +91,9 @@ public class ScriptTrait extends Trait {
}).beginWithFuture();
}
/**
* Removes the given script file names.
*/
public void removeScripts(List<String> scripts) {
files.removeAll(scripts);
Iterator<RunnableScript> itr = runnableScripts.iterator();
@ -99,6 +120,9 @@ public class ScriptTrait extends Trait {
}
}
/**
* Whether the file exists and can be compiled by the system {@link ScriptCompiler}.
*/
public boolean validateFile(String file) {
File f = new File(JavaPlugin.getPlugin(Citizens.class).getScriptFolder(), file);
if (!f.exists() || !f.getParentFile().equals(JavaPlugin.getPlugin(Citizens.class).getScriptFolder())) {

View File

@ -10,6 +10,9 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists {@link Sheep} metadata.
*/
@TraitName("sheeptrait")
public class SheepTrait extends Trait {
@Persist("color")
@ -22,16 +25,12 @@ public class SheepTrait extends Trait {
}
@EventHandler
public void onPlayerShearEntityEvent(PlayerShearEntityEvent event) {
private void onPlayerShearEntityEvent(PlayerShearEntityEvent event) {
if (npc != null && npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getEntity()))) {
event.setCancelled(true);
}
}
@Override
public void onSpawn() {
}
@Override
public void run() {
if (npc.getEntity() instanceof Sheep) {
@ -41,10 +40,16 @@ public class SheepTrait extends Trait {
}
}
/**
* @see Sheep#setColor(DyeColor)
*/
public void setColor(DyeColor color) {
this.color = color;
}
/**
* @see Sheep#setSheared(boolean)
*/
public void setSheared(boolean sheared) {
this.sheared = sheared;
}

View File

@ -5,6 +5,11 @@ import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.npc.skin.SkinnableEntity;
/**
* Persists skin layers that should/should not be visible on the NPC skin.
*
* @see Layer
*/
@TraitName("skinlayers")
public class SkinLayers extends Trait {
@Persist("cape")

View File

@ -9,6 +9,11 @@ import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.Messaging;
import net.citizensnpcs.util.Messages;
/**
* Persists Slime size.
*
* @see Slime#setSize(int)
*/
@TraitName("slimesize")
public class SlimeSize extends Trait {
@Persist
@ -33,6 +38,9 @@ public class SlimeSize extends Trait {
slime = true;
}
/**
* @see Slime#setSize(int)
*/
public void setSize(int size) {
this.size = size;
if (slime)

View File

@ -1,5 +1,8 @@
package net.citizensnpcs.trait;
/**
* Representing a state that can be toggled between enabled/disabled.
*/
public interface Toggleable {
public boolean toggle();
}

View File

@ -2,13 +2,18 @@ package net.citizensnpcs.trait;
import org.bukkit.entity.Villager;
import org.bukkit.entity.Villager.Profession;
import org.bukkit.entity.ZombieVillager;
import net.citizensnpcs.api.exception.NPCLoadException;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey;
import org.bukkit.entity.ZombieVillager;
/**
* Persists the Villager profession metadata.
*
* @see Profession
*/
@TraitName("profession")
public class VillagerProfession extends Trait {
private Profession profession = Profession.FARMER;

View File

@ -7,6 +7,11 @@ import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.util.NMS;
/**
* Persists {@link Wither} metadata.
*
* @see Wither
*/
@TraitName("withertrait")
public class WitherTrait extends Trait {
@Persist("charged")
@ -20,10 +25,6 @@ public class WitherTrait extends Trait {
return charged;
}
@Override
public void onSpawn() {
}
@Override
public void run() {
if (npc.getEntity() instanceof Wither) {

View File

@ -7,6 +7,11 @@ import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
/**
* Persists {@link Wolf} metadata.
*
* @see Wolf
*/
@TraitName("wolfmodifiers")
public class WolfModifiers extends Trait {
@Persist("angry")

View File

@ -11,6 +11,11 @@ import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.api.util.DataKey;
/**
* Persists {@link Sheep} wool color metadata.
*
* @see Sheep
*/
@TraitName("woolcolor")
public class WoolColor extends Trait {
private DyeColor color = DyeColor.WHITE;
@ -30,9 +35,10 @@ public class WoolColor extends Trait {
}
@EventHandler
public void onSheepDyeWool(SheepDyeWoolEvent event) {
if (npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getEntity())))
private void onSheepDyeWool(SheepDyeWoolEvent event) {
if (npc.equals(CitizensAPI.getNPCRegistry().getNPC(event.getEntity()))) {
event.setCancelled(true);
}
}
@Override

View File

@ -35,6 +35,9 @@ import net.citizensnpcs.trait.Toggleable;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Util;
/**
* Persists text metadata, i.e. text that will be said by an NPC on certain triggers.
*/
@TraitName("text")
public class Text extends Trait implements Runnable, Toggleable, Listener, ConversationAbandonedListener {
private final Map<UUID, Long> cooldowns = Maps.newHashMap();
@ -53,7 +56,13 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
this.plugin = CitizensAPI.getPlugin();
}
void add(String string) {
/**
* Adds a piece of text that will be said by the NPC.
*
* @param string
* the text to say
*/
public void add(String string) {
text.add(string);
}
@ -61,10 +70,21 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
public void conversationAbandoned(ConversationAbandonedEvent event) {
}
void edit(int index, String newText) {
/**
* Edit the text at a given index to a new text.
*
* @param index
* the text's index
* @param newText
* the new text to use
*/
public void edit(int index, String newText) {
text.set(index, newText);
}
/**
* Builds a text editor in game for the supplied {@link Player}.
*/
public Editor getEditor(final Player player) {
final Conversation conversation = new ConversationFactory(plugin).addConversationAbandonedListener(this)
.withLocalEcho(false).withEscapeSequence("/npc text").withEscapeSequence("exit").withModality(false)
@ -84,7 +104,10 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
};
}
boolean hasIndex(int index) {
/**
* @return whether there is text at a certain index
*/
public boolean hasIndex(int index) {
return index >= 0 && text.size() > index;
}
@ -111,7 +134,7 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
}
@EventHandler
public void onRightClick(NPCRightClickEvent event) {
private void onRightClick(NPCRightClickEvent event) {
if (!event.getNPC().equals(npc))
return;
String localPattern = itemInHandPattern.equals("default") ? Setting.TALK_ITEM.asString() : itemInHandPattern;
@ -124,7 +147,10 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
text.addAll(Setting.DEFAULT_TEXT.asList());
}
void remove(int index) {
/**
* Remove text at a given index.
*/
public void remove(int index) {
text.remove(index);
}
@ -200,7 +226,13 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
return true;
}
void setDelay(int delay) {
/**
* Set the text delay between messages.
*
* @param delay
* the delay in ticks
*/
public void setDelay(int delay) {
this.delay = delay;
}
@ -208,7 +240,12 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
itemInHandPattern = pattern;
}
void setRange(double range) {
/**
* Set the range in blocks before text will be sent.
*
* @param range
*/
public void setRange(double range) {
this.range = range;
}
@ -216,16 +253,25 @@ public class Text extends Trait implements Runnable, Toggleable, Listener, Conve
return talkClose;
}
/**
* Toggles talking to nearby Players.
*/
@Override
public boolean toggle() {
return (talkClose = !talkClose);
}
boolean toggleRandomTalker() {
/**
* Toggles talking at random intervals.
*/
public boolean toggleRandomTalker() {
return (randomTalker = !randomTalker);
}
boolean toggleRealisticLooking() {
/**
* Toggles requiring line of sight before talking.
*/
public boolean toggleRealisticLooking() {
return (realisticLooker = !realisticLooker);
}

View File

@ -15,10 +15,22 @@ import net.citizensnpcs.api.npc.MemoryNPCDataStore;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.npc.NPCRegistry;
/**
* A helper class for storing a number of entity markers. By default an entity marker is a non-persisted EnderSignal.
*/
public class EntityMarkers<T> {
private final Map<T, Entity> markers = Maps.newHashMap();
private final NPCRegistry registry = CitizensAPI.createAnonymousNPCRegistry(new MemoryNPCDataStore());
/**
* Creates and persists (in memory) an {@link Entity} marker.
*
* @param marker
* the storage marker
* @param at
* the spawn location
* @return the created entity
*/
public Entity createMarker(T marker, Location at) {
Entity entity = spawnMarker(at.getWorld(), at);
if (entity == null)
@ -41,6 +53,15 @@ public class EntityMarkers<T> {
}
}
/**
* Spawns a marker {@link Entity} without storing it for later use.
*
* @param world
* the world (unused currently)
* @param at
* the location
* @return the spawned entity
*/
public Entity spawnMarker(World world, Location at) {
NPC npc = registry.createNPC(EntityType.ENDER_SIGNAL, "");
npc.spawn(at.clone().add(0.5, 0, 0.5), SpawnReason.CREATE);

View File

@ -1,5 +1,6 @@
package net.citizensnpcs.trait.waypoint;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@ -43,6 +44,12 @@ import net.citizensnpcs.trait.waypoint.WaypointProvider.EnumerableWaypointProvid
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Util;
/**
* Stores guided waypoint info. Guided waypoints are a list of {@link Waypoint}s that will be navigated between
* randomly. Helper waypoints can be used to guide navigation between the random waypoints i.e. navigating between guide
* waypoints. For example, you might have a "realistic" NPC that walks between houses using helper waypoints placed
* along the roads.
*/
public class GuidedWaypointProvider implements EnumerableWaypointProvider {
private final List<Waypoint> available = Lists.newArrayList();
private GuidedAIGoal currentGoal;
@ -51,6 +58,26 @@ public class GuidedWaypointProvider implements EnumerableWaypointProvider {
private boolean paused;
private PRTree<Region3D<Waypoint>> tree = PRTree.create(new Region3D.Converter<Waypoint>(), 30);
public void addHelperWaypoint(Waypoint helper) {
helpers.add(helper);
rebuildTree();
}
public void addHelperWaypoints(Collection<Waypoint> helper) {
helpers.addAll(helper);
rebuildTree();
}
public void addWaypoint(Waypoint waypoint) {
available.add(waypoint);
rebuildTree();
}
public void addWaypoints(Collection<Waypoint> waypoint) {
available.addAll(waypoint);
rebuildTree();
}
@Override
public WaypointEditor createEditor(final CommandSender sender, CommandContext args) {
if (!(sender instanceof Player)) {
@ -233,6 +260,9 @@ public class GuidedWaypointProvider implements EnumerableWaypointProvider {
this.paused = paused;
}
/**
* Returns available and helper waypoints.
*/
@Override
public Iterable<Waypoint> waypoints() {
return Iterables.concat(available, helpers);

View File

@ -40,6 +40,9 @@ import net.citizensnpcs.trait.waypoint.triggers.TriggerEditPrompt;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Util;
/**
* An ordered list of {@link Waypoint}s to walk between.
*/
public class LinearWaypointProvider implements EnumerableWaypointProvider {
private LinearWaypointGoal currentGoal;
private NPC npc;
@ -136,6 +139,9 @@ public class LinearWaypointProvider implements EnumerableWaypointProvider {
}
}
/**
* Returns the modifiable list of waypoints.
*/
@Override
public Iterable<Waypoint> waypoints() {
return waypoints;

View File

@ -1,5 +1,6 @@
package net.citizensnpcs.trait.waypoint;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
@ -31,6 +32,10 @@ import net.citizensnpcs.api.util.cuboid.QuadTree;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.Util;
/**
* A wandering waypoint provider that wanders between either a box centered at the current location or inside a region
* defined by a list of boxes.
*/
public class WanderWaypointProvider implements WaypointProvider, Supplier<QuadTree>, Function<NPC, Location> {
private WanderGoal currentGoal;
private NPC npc;
@ -43,6 +48,16 @@ public class WanderWaypointProvider implements WaypointProvider, Supplier<QuadTr
@Persist
public int yrange = DEFAULT_YRANGE;
public void addRegionCentre(Location centre) {
regionCentres.add(centre);
recalculateTree();
}
public void addRegionCentres(Collection<Location> centre) {
regionCentres.addAll(centre);
recalculateTree();
}
@Override
public Location apply(NPC npc) {
Location closestCentre = null;
@ -218,6 +233,16 @@ public class WanderWaypointProvider implements WaypointProvider, Supplier<QuadTr
}
}
public void removeRegionCentre(Location centre) {
regionCentres.remove(centre);
recalculateTree();
}
public void removeRegionCentres(Collection<Location> centre) {
regionCentres.removeAll(centre);
recalculateTree();
}
@Override
public void save(DataKey key) {
}
@ -262,6 +287,5 @@ public class WanderWaypointProvider implements WaypointProvider, Supplier<QuadTr
}
private static final int DEFAULT_XRANGE = 3;
private static final int DEFAULT_YRANGE = 25;
}

View File

@ -19,12 +19,18 @@ import net.citizensnpcs.trait.waypoint.triggers.WaypointTrigger;
import net.citizensnpcs.trait.waypoint.triggers.WaypointTriggerRegistry;
import net.citizensnpcs.util.Messages;
/**
* Represents a {@link Location} with a number of {@link WaypointTriggers} that activate on reaching the location.
*/
public class Waypoint implements Locatable {
@Persist(required = true)
private Location location;
@Persist
private List<WaypointTrigger> triggers;
/**
* For persistence - avoid using otherwise.
*/
public Waypoint() {
}
@ -47,6 +53,9 @@ public class Waypoint implements Locatable {
Messaging.sendTr(sender, Messages.WAYPOINT_TRIGGER_LIST, base);
}
/**
* Returns the distance in blocks to another waypoint.
*/
public double distance(Waypoint dest) {
return location.distance(dest.location);
}
@ -93,6 +102,9 @@ public class Waypoint implements Locatable {
return prime * result + ((triggers == null) ? 0 : triggers.hashCode());
}
/**
* Runs waypoint triggers for the given NPC.
*/
public void onReach(NPC npc) {
if (triggers == null)
return;

View File

@ -1,53 +0,0 @@
package net.citizensnpcs.trait.waypoint;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import com.google.common.collect.Maps;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.SpawnReason;
import net.citizensnpcs.api.npc.MemoryNPCDataStore;
import net.citizensnpcs.api.npc.NPC;
public class WaypointMarkers {
private final Map<Waypoint, Entity> waypointMarkers = Maps.newHashMap();
private final World world;
public WaypointMarkers(World world) {
this.world = world;
}
public Entity createWaypointMarker(Waypoint waypoint) {
Entity entity = spawnMarker(world, waypoint.getLocation().clone().add(0, 1, 0));
if (entity == null)
return null;
waypointMarkers.put(waypoint, entity);
return entity;
}
public void destroyWaypointMarkers() {
for (Entity entity : waypointMarkers.values()) {
entity.remove();
}
waypointMarkers.clear();
}
public void removeWaypointMarker(Waypoint waypoint) {
Entity entity = waypointMarkers.remove(waypoint);
if (entity != null) {
entity.remove();
}
}
public Entity spawnMarker(World world, Location at) {
NPC npc = CitizensAPI.createAnonymousNPCRegistry(new MemoryNPCDataStore()).createNPC(EntityType.ENDER_SIGNAL,
"");
npc.spawn(at, SpawnReason.CREATE);
return npc.getEntity();
}
}

View File

@ -38,7 +38,7 @@ public class Waypoints extends Trait {
public void describeProviders(CommandSender sender) {
Messaging.sendTr(sender, Messages.AVAILABLE_WAYPOINT_PROVIDERS);
for (String name : providers.keySet()) {
for (String name : PROVIDERS.keySet()) {
Messaging.send(sender, " - " + StringHelper.wrap(name));
}
}
@ -67,7 +67,7 @@ public class Waypoints extends Trait {
public void load(DataKey key) throws NPCLoadException {
provider = null;
providerName = key.getString("provider", "linear");
for (Entry<String, Class<? extends WaypointProvider>> entry : providers.entrySet()) {
for (Entry<String, Class<? extends WaypointProvider>> entry : PROVIDERS.entrySet()) {
if (entry.getKey().equals(providerName)) {
provider = create(entry.getValue());
break;
@ -102,7 +102,7 @@ public class Waypoints extends Trait {
*/
public boolean setWaypointProvider(String name) {
name = name.toLowerCase();
Class<? extends WaypointProvider> clazz = providers.get(name);
Class<? extends WaypointProvider> clazz = PROVIDERS.get(name);
if (provider != null) {
provider.onRemove();
}
@ -124,14 +124,14 @@ public class Waypoints extends Trait {
* The name of the waypoint provider
*/
public static void registerWaypointProvider(Class<? extends WaypointProvider> clazz, String name) {
providers.put(name, clazz);
PROVIDERS.put(name, clazz);
}
private static final Map<String, Class<? extends WaypointProvider>> providers = Maps.newHashMap();
private static final Map<String, Class<? extends WaypointProvider>> PROVIDERS = Maps.newHashMap();
static {
providers.put("linear", LinearWaypointProvider.class);
providers.put("wander", WanderWaypointProvider.class);
providers.put("guided", GuidedWaypointProvider.class);
PROVIDERS.put("linear", LinearWaypointProvider.class);
PROVIDERS.put("wander", WanderWaypointProvider.class);
PROVIDERS.put("guided", GuidedWaypointProvider.class);
}
}

View File

@ -11,18 +11,23 @@ import net.citizensnpcs.api.persistence.PersistenceLoader;
import net.citizensnpcs.api.persistence.Persister;
import net.citizensnpcs.api.util.DataKey;
/**
* Registers valid {@link WaypointTrigger} classes and their chat configuration prompts. WaypointTriggers are persisted
* using {@link PersistenceLoader}.
*
*/
public class WaypointTriggerRegistry implements Persister<WaypointTrigger> {
@Override
public WaypointTrigger create(DataKey root) {
String type = root.getString("type");
Class<? extends WaypointTrigger> clazz = triggers.get(type);
Class<? extends WaypointTrigger> clazz = TRIGGERS.get(type);
return clazz == null ? null : PersistenceLoader.load(clazz, root);
}
@Override
public void save(WaypointTrigger instance, DataKey root) {
PersistenceLoader.save(instance, root);
for (Map.Entry<String, Class<? extends WaypointTrigger>> entry : triggers.entrySet()) {
for (Map.Entry<String, Class<? extends WaypointTrigger>> entry : TRIGGERS.entrySet()) {
if (entry.getValue() == instance.getClass()) {
root.setString("type", entry.getKey());
break;
@ -32,16 +37,16 @@ public class WaypointTriggerRegistry implements Persister<WaypointTrigger> {
public static void addTrigger(String name, Class<? extends WaypointTrigger> triggerClass,
Class<? extends WaypointTriggerPrompt> promptClass) {
triggers.put(name, triggerClass);
triggerPrompts.put(name, promptClass);
TRIGGERS.put(name, triggerClass);
TRIGGER_PROMPTS.put(name, promptClass);
}
public static String describeValidTriggerNames() {
return Joiner.on(", ").join(triggerPrompts.keySet());
return Joiner.on(", ").join(TRIGGER_PROMPTS.keySet());
}
public static Prompt getTriggerPromptFrom(String input) {
Class<? extends Prompt> promptClass = triggerPrompts.get(input);
Class<? extends Prompt> promptClass = TRIGGER_PROMPTS.get(input);
if (promptClass == null)
return null;
try {
@ -51,8 +56,8 @@ public class WaypointTriggerRegistry implements Persister<WaypointTrigger> {
}
}
private static final Map<String, Class<? extends Prompt>> triggerPrompts = Maps.newHashMap();
private static final Map<String, Class<? extends WaypointTrigger>> triggers = Maps.newHashMap();
private static final Map<String, Class<? extends Prompt>> TRIGGER_PROMPTS = Maps.newHashMap();
private static final Map<String, Class<? extends WaypointTrigger>> TRIGGERS = Maps.newHashMap();
static {
addTrigger("animation", AnimationTrigger.class, AnimationTriggerPrompt.class);

View File

@ -5,10 +5,9 @@ import org.apache.commons.lang.builder.HashCodeBuilder;
import org.bukkit.Bukkit;
import org.bukkit.Location;
/*
* Anchor object which holds a Location with a name to identify.
/**
* A named {@link Location}.
*/
public class Anchor {
private Location location;
private final String name;
@ -16,13 +15,6 @@ public class Anchor {
// Needed for Anchors defined that can't currently have a valid 'Location'
private final String unloaded_value;
// Allow construction of anchor for unloaded worlds
public Anchor(String name, String unloaded_value) {
this.location = null;
this.unloaded_value = unloaded_value;
this.name = name;
}
public Anchor(String name, Location location) {
this.location = location;
this.name = name;
@ -30,19 +22,11 @@ public class Anchor {
+ location.getZ();
}
public boolean isLoaded() {
return location != null;
}
public boolean load() {
try {
String[] parts = getUnloadedValue();
this.location = new Location(Bukkit.getWorld(parts[0]), Double.valueOf(parts[1]), Double.valueOf(parts[2]),
Double.valueOf(parts[3]));
} catch (Exception e) {
// Still not able to be loaded
}
return location != null;
// Allow construction of anchor for unloaded worlds
public Anchor(String name, String unloaded_value) {
this.location = null;
this.unloaded_value = unloaded_value;
this.name = name;
}
@Override
@ -81,7 +65,30 @@ public class Anchor {
return new HashCodeBuilder(13, 21).append(name).toHashCode();
}
// A friendly representation for use in saves.yml
public boolean isLoaded() {
return location != null;
}
/**
* Attempts to load the unloaded value of the stored {@link Location}.
*
* @see #getUnloadedValue()
* @return whether the unloaded value could be loaded
*/
public boolean load() {
try {
String[] parts = getUnloadedValue();
this.location = new Location(Bukkit.getWorld(parts[0]), Double.valueOf(parts[1]), Double.valueOf(parts[2]),
Double.valueOf(parts[3]));
} catch (Exception e) {
// Still not able to be loaded
}
return location != null;
}
/**
* @return A string representation for use in saves.yml
*/
public String stringValue() {
return name + ';' + unloaded_value;
}

View File

@ -56,5 +56,4 @@ public class Pose {
public String toString() {
return "Pose{Name='" + name + "';Pitch='" + pitch + "';Yaw='" + yaw + "';}";
}
}