├── .gitignore ├── src └── main │ └── java │ └── net │ └── citizensnpcs │ └── api │ ├── npc │ ├── RemoveReason.java │ ├── NPCSelector.java │ ├── templates │ │ ├── TemplateWorkspace.java │ │ ├── CommandListExecutor.java │ │ └── CommandEventAction.java │ ├── MemoryNPCDataStore.java │ └── NPCDataStore.java │ ├── ai │ ├── TargetType.java │ ├── event │ │ ├── NavigatorCallback.java │ │ ├── CancelReason.java │ │ ├── NavigationCompleteEvent.java │ │ ├── NavigationBeginEvent.java │ │ ├── NavigationReplaceEvent.java │ │ ├── NavigationEvent.java │ │ ├── NavigationCancelEvent.java │ │ └── NavigationStuckEvent.java │ ├── PrioritisableGoal.java │ ├── PathfinderType.java │ ├── EntityTarget.java │ ├── StuckAction.java │ ├── flocking │ │ ├── NPCFlock.java │ │ ├── FlockBehavior.java │ │ ├── AlignmentBehavior.java │ │ ├── CohesionBehavior.java │ │ ├── GroupNPCFlock.java │ │ ├── SeparationBehavior.java │ │ ├── RadiusNPCFlock.java │ │ └── Flocker.java │ ├── tree │ │ ├── ParallelBehavior.java │ │ ├── InstantBehavior.java │ │ ├── BehaviorStatus.java │ │ ├── ParallelComposite.java │ │ ├── ParallelBehaviorWrapper.java │ │ ├── InverterDecorator.java │ │ ├── BehaviorGoalAdapter.java │ │ ├── TimeoutDecorator.java │ │ ├── TimerDecorator.java │ │ ├── CoalescedBehavior.java │ │ ├── Callback.java │ │ ├── RetryDecorator.java │ │ ├── Loop.java │ │ ├── ForwardingBehaviorGoalAdapter.java │ │ ├── IfElse.java │ │ ├── StatusMapper.java │ │ ├── Behavior.java │ │ └── Selectors.java │ ├── speech │ │ ├── event │ │ │ ├── SpeechTargetedEvent.java │ │ │ ├── SpeechBystanderEvent.java │ │ │ ├── NPCSpeechEvent.java │ │ │ └── SpeechEvent.java │ │ ├── SpeechController.java │ │ └── Talkable.java │ ├── AttackStrategy.java │ ├── AbstractPathStrategy.java │ ├── GoalSelector.java │ ├── Goal.java │ ├── PathStrategy.java │ ├── TeleportStuckAction.java │ ├── goals │ │ ├── MoveToGoal.java │ │ └── FollowPathGoal.java │ └── SimpleGoalEntry.java │ ├── hpastar │ ├── Direction.java │ ├── HPAEntrance.java │ ├── HPAGraphEdge.java │ ├── ClusterNode.java │ ├── AStarSolution.java │ ├── ReversableAStarNode.java │ ├── HPAGraphAStarNode.java │ └── HPAGraphNode.java │ ├── util │ ├── FileStorage.java │ ├── schedulers │ │ ├── SchedulerTask.java │ │ └── adapter │ │ │ ├── SpigotSchedulerTask.java │ │ │ └── FoliaSchedulerTask.java │ ├── Storage.java │ ├── PermissionUtil.java │ └── EntityDim.java │ ├── gui │ ├── ForwardingInventory.java │ ├── ClickHandlers.java │ ├── MenuSlots.java │ ├── MenuPatterns.java │ ├── MenuTransitions.java │ ├── InjectContext.java │ ├── InventoryMenuPage.java │ ├── InventoryMenuTransition.java │ ├── MenuPattern.java │ ├── ClickHandler.java │ ├── Menu.java │ ├── PercentageSlotHandler.java │ ├── MenuTransition.java │ ├── InventoryMenuPattern.java │ ├── MenuSlot.java │ └── MenuContext.java │ ├── astar │ ├── Agent.java │ ├── Plan.java │ ├── AStarStorage.java │ ├── pathfinder │ │ ├── BlockSource.java │ │ ├── BlockExaminer.java │ │ ├── VectorGoal.java │ │ ├── ChunkSnapshotBlockSource.java │ │ ├── ChunkBlockSource.java │ │ └── PathPoint.java │ ├── AStarGoal.java │ ├── AStarNode.java │ └── SimpleAStarStorage.java │ ├── event │ ├── SpawnReason.java │ ├── DespawnReason.java │ ├── CitizensEvent.java │ ├── CitizensEnableEvent.java │ ├── NPCTraitEvent.java │ ├── CitizensReloadEvent.java │ ├── CitizensPreReloadEvent.java │ ├── NPCCreateEvent.java │ ├── NPCRemoveEvent.java │ ├── NPCAddTraitEvent.java │ ├── NPCRemoveTraitEvent.java │ ├── NPCEvent.java │ ├── NPCLeftClickEvent.java │ ├── NPCCloneEvent.java │ ├── NPCUnlinkFromPlayerEvent.java │ ├── NPCLinkToPlayerEvent.java │ ├── CommandSenderCloneNPCEvent.java │ ├── NPCRemoveByCommandSenderEvent.java │ ├── NPCDamageByBlockEvent.java │ ├── NPCDamageEntityEvent.java │ ├── NPCPistonPushEvent.java │ ├── PlayerCreateNPCEvent.java │ ├── NPCDamageByEntityEvent.java │ ├── NPCCollisionEvent.java │ ├── CitizensSerialiseMetaEvent.java │ ├── NPCRightClickEvent.java │ ├── CitizensDeserialiseMetaEvent.java │ ├── NPCSelectEvent.java │ ├── NPCRenameEvent.java │ ├── CitizensGetSelectedNPCEvent.java │ ├── PlayerCloneNPCEvent.java │ ├── NPCLookCloseChangeTargetEvent.java │ ├── NPCSeenByPlayerEvent.java │ ├── NPCDespawnEvent.java │ ├── NPCTraitCommandAttachEvent.java │ ├── NPCTraitCommandDetachEvent.java │ ├── NPCCombustByEntityEvent.java │ ├── NPCCombustByBlockEvent.java │ ├── NPCCombustEvent.java │ ├── NPCDeathEvent.java │ ├── NPCOpenDoorEvent.java │ ├── NPCOpenGateEvent.java │ ├── NPCTeleportEvent.java │ ├── NPCCommandDispatchEvent.java │ ├── NPCVehicleDamageEvent.java │ ├── NPCClickEvent.java │ ├── NPCPushEvent.java │ ├── NPCKnockbackEvent.java │ ├── EntityTargetNPCEvent.java │ ├── NPCDamageEvent.java │ ├── NPCSpawnEvent.java │ ├── CommandSenderCreateNPCEvent.java │ └── NPCMoveEvent.java │ ├── command │ ├── exception │ │ ├── ServerCommandException.java │ │ ├── UnhandledCommandException.java │ │ ├── WrappedCommandException.java │ │ ├── RequirementMissingException.java │ │ ├── NoPermissionsException.java │ │ ├── CommandUsageException.java │ │ └── CommandException.java │ ├── Requirements.java │ ├── Flag.java │ ├── CommandAnnotationProcessor.java │ ├── Injector.java │ └── CommandMessages.java │ ├── exception │ └── NPCLoadException.java │ ├── persistence │ ├── Persistable.java │ ├── ItemStackPersister.java │ ├── UUIDPersister.java │ ├── DelegatePersistence.java │ ├── VectorPersister.java │ ├── Vector3fPersister.java │ ├── EulerAnglePersister.java │ ├── QuaternionfPersister.java │ ├── NamespacedKeyPersister.java │ ├── ComponentPersister.java │ ├── Persister.java │ ├── PotionEffectPersister.java │ ├── PersisterRegistry.java │ └── Persist.java │ ├── trait │ ├── TraitName.java │ ├── TraitEventHandler.java │ ├── trait │ │ ├── Spawned.java │ │ └── MobType.java │ ├── TraitTemplateParser.java │ └── TraitFactory.java │ ├── NMSHelper.java │ └── expr │ ├── ExpressionEngine.java │ └── CompiledExpression.java ├── .github └── FUNDING.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /target 3 | .classpath 4 | .project 5 | /.settings 6 | CitizensAPI.jar 7 | *.lnk 8 | .idea/ 9 | *.iml 10 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/RemoveReason.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc; 2 | 3 | public enum RemoveReason { 4 | DESTROYED, 5 | REMOVAL; 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/TargetType.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | public enum TargetType { 4 | ENTITY, 5 | LOCATION, 6 | NONE 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/Direction.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | public enum Direction { 4 | EAST, 5 | NORTH, 6 | SOUTH, 7 | WEST; 8 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/HPAEntrance.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | public class HPAEntrance { 4 | int maxX; 5 | int maxZ; 6 | int minX; 7 | int minZ; 8 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/FileStorage.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util; 2 | 3 | import java.io.File; 4 | 5 | public interface FileStorage extends Storage { 6 | File getFile(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigatorCallback.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | public interface NavigatorCallback { 4 | void onCompletion(CancelReason cancelReason); 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/ForwardingInventory.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import org.bukkit.inventory.Inventory; 4 | 5 | public interface ForwardingInventory { 6 | Inventory getWrapped(); 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/Agent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | /** 4 | * An abstract agent that will complete a {@link Plan} as returned by {@link AStarGoal}. 5 | */ 6 | public interface Agent { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/PrioritisableGoal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | /** 4 | * A dynamically prioritisable {@link Goal}. 5 | */ 6 | public interface PrioritisableGoal extends Goal { 7 | int getPriority(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/SpawnReason.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | public enum SpawnReason { 4 | CHUNK_LOAD, 5 | COMMAND, 6 | CREATE, 7 | PLUGIN, 8 | RESPAWN, 9 | TIMED_RESPAWN; 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/CancelReason.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | public enum CancelReason { 4 | NPC_DESPAWNED, 5 | PLUGIN, 6 | REPLACE, 7 | STUCK, 8 | TARGET_DIED, 9 | TARGET_MOVED_WORLD 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/ServerCommandException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | public class ServerCommandException extends CommandException { 4 | private static final long serialVersionUID = 9120268556899197316L; 5 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/DespawnReason.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | public enum DespawnReason { 4 | CHUNK_UNLOAD, 5 | DEATH, 6 | PENDING_RESPAWN, 7 | PLUGIN, 8 | RELOAD, 9 | REMOVAL, 10 | WORLD_UNLOAD; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/UnhandledCommandException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | public class UnhandledCommandException extends CommandException { 4 | private static final long serialVersionUID = 3370887306593968091L; 5 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/PathfinderType.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | public enum PathfinderType { 4 | CITIZENS, 5 | CITIZENS_ASYNC, 6 | MINECRAFT, 7 | PLUGIN; 8 | 9 | public boolean isCitizens() { 10 | return name().startsWith("CITIZENS"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/WrappedCommandException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | public class WrappedCommandException extends CommandException { 4 | public WrappedCommandException(Throwable t) { 5 | super(t); 6 | } 7 | 8 | private static final long serialVersionUID = -4075721444847778918L; 9 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/schedulers/SchedulerTask.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util.schedulers; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | 5 | public interface SchedulerTask { 6 | void cancel(); 7 | 8 | Object getOriginalTask(); 9 | 10 | Plugin getPlugin(); 11 | 12 | boolean isCancelled(); 13 | 14 | boolean isRepeating(); 15 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/RequirementMissingException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | public class RequirementMissingException extends CommandException { 4 | public RequirementMissingException(String message) { 5 | super(message); 6 | } 7 | 8 | private static final long serialVersionUID = -4299721983654504028L; 9 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/Plan.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | /** 4 | * An abstract plan returned by the {@link AStarGoal} that should be run until completion. 5 | */ 6 | public interface Plan { 7 | boolean isComplete(); 8 | 9 | /** 10 | * Updates the plan. Should be run ideally every tick. 11 | */ 12 | void update(Agent agent); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/exception/NPCLoadException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.exception; 2 | 3 | /** 4 | * Thrown when an NPC fails to load properly. 5 | */ 6 | public class NPCLoadException extends Exception { 7 | public NPCLoadException(String msg) { 8 | super(msg); 9 | } 10 | 11 | private static final long serialVersionUID = -4604062224372942561L; 12 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Event; 4 | 5 | /** 6 | * Represents an event thrown by Citizens. 7 | */ 8 | public abstract class CitizensEvent extends Event { 9 | protected CitizensEvent() { 10 | } 11 | 12 | protected CitizensEvent(boolean async) { 13 | super(async); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/ClickHandlers.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.METHOD }) 10 | public @interface ClickHandlers { 11 | ClickHandler[] value(); 12 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/EntityTarget.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import org.bukkit.entity.Entity; 4 | 5 | public interface EntityTarget { 6 | /** 7 | * @return The {@link Entity} being targeted. 8 | */ 9 | Entity getTarget(); 10 | 11 | /** 12 | * @return Whether the entity target should be attacked once within range 13 | */ 14 | boolean isAggressive(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/Persistable.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import net.citizensnpcs.api.util.DataKey; 4 | 5 | /** 6 | * An Object that can be serialised using {@link DataKey}s. {@link PersistenceLoader} will call these methods when 7 | * serialising objects. 8 | */ 9 | public interface Persistable { 10 | public void load(DataKey root); 11 | 12 | public void save(DataKey root); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/NoPermissionsException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | import net.citizensnpcs.api.command.CommandMessages; 4 | 5 | public class NoPermissionsException extends CommandException { 6 | public NoPermissionsException() { 7 | super(CommandMessages.NO_PERMISSION); 8 | } 9 | 10 | private static final long serialVersionUID = -602374621030168291L; 11 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuSlots.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 10 | public @interface MenuSlots { 11 | MenuSlot[] value(); 12 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuPatterns.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 10 | public @interface MenuPatterns { 11 | MenuPattern[] value(); 12 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensEnableEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | public class CitizensEnableEvent extends CitizensEvent { 6 | @Override 7 | public HandlerList getHandlers() { 8 | return handlers; 9 | } 10 | 11 | public static HandlerList getHandlerList() { 12 | return handlers; 13 | } 14 | 15 | private static final HandlerList handlers = new HandlerList(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCTraitEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import net.citizensnpcs.api.npc.NPC; 4 | import net.citizensnpcs.api.trait.Trait; 5 | 6 | public abstract class NPCTraitEvent extends NPCEvent { 7 | private final Trait trait; 8 | 9 | protected NPCTraitEvent(NPC npc, Trait trait) { 10 | super(npc); 11 | this.trait = trait; 12 | } 13 | 14 | public Trait getTrait() { 15 | return trait; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuTransitions.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 10 | public @interface MenuTransitions { 11 | MenuTransition[] value(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/InjectContext.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Marker annotation to inject context variables at runtime into {@link InventoryMenuPage}s. 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ ElementType.FIELD }) 13 | public @interface InjectContext { 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/NPCSelector.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc; 2 | 3 | import org.bukkit.command.CommandSender; 4 | 5 | /** 6 | * Manages the 'selected {@link NPC}' for the server. {@link NPC}s can be selected using selection-item specified in the 7 | * config or via commands. 8 | */ 9 | public interface NPCSelector { 10 | void deselect(CommandSender sender); 11 | 12 | NPC getSelected(CommandSender sender); 13 | 14 | void select(CommandSender sender, NPC npc); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/StuckAction.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import net.citizensnpcs.api.npc.NPC; 4 | 5 | public interface StuckAction { 6 | /** 7 | * Called when the {@link Navigator} reports that it is stuck. 8 | * 9 | * @param npc 10 | * The stuck {@link NPC} 11 | * @param navigator 12 | * The navigator 13 | * @return Whether to continue navigation 14 | */ 15 | boolean run(NPC npc, Navigator navigator); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/NPCFlock.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | /** 8 | * Represents a 'flock' of NPCs to be used as input to a {@link Flocker}. 9 | * 10 | * @see RadiusNPCFlock 11 | * @see GroupNPCFlock 12 | */ 13 | public interface NPCFlock { 14 | /** 15 | * Returns the NPCs to be considered part of a flock. 16 | */ 17 | public Collection getNearby(NPC npc); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/ParallelBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * A marker interface for {@link Behavior}s that indicates to any parent nodes that the behavior can be run in 5 | * parallel along with other behaviors. 6 | *

7 | * Parallel behaviors will not affect the success or failure status of any composite nodes; the return 8 | * {@link BehaviorStatus} will only act as a terminal status or an indication to remove the parallel node. 9 | */ 10 | public interface ParallelBehavior { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/event/SpeechTargetedEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech.event; 2 | 3 | import net.citizensnpcs.api.ai.speech.SpeechContext; 4 | import net.citizensnpcs.api.ai.speech.Talkable; 5 | 6 | /** 7 | * Represents an event where a Talkable entity speaks to another Talkable entity. 8 | * 9 | */ 10 | public class SpeechTargetedEvent extends SpeechEvent { 11 | public SpeechTargetedEvent(Talkable target, SpeechContext context, String message) { 12 | super(target, context, message); 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensReloadEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | /** 6 | * Called when Citizens is reloaded. 7 | */ 8 | public class CitizensReloadEvent extends CitizensEvent { 9 | @Override 10 | public HandlerList getHandlers() { 11 | return handlers; 12 | } 13 | 14 | public static HandlerList getHandlerList() { 15 | return handlers; 16 | } 17 | 18 | private static final HandlerList handlers = new HandlerList(); 19 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/TraitName.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * A helper annotation to specify trait name for {@link TraitInfo}. Should be placed on the class implementing 10 | * {@link Trait}. 11 | */ 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Target(ElementType.TYPE) 14 | public @interface TraitName { 15 | String value(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensPreReloadEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | /** 6 | * Called just before Citizens is reloaded. 7 | */ 8 | public class CitizensPreReloadEvent extends CitizensEvent { 9 | @Override 10 | public HandlerList getHandlers() { 11 | return handlers; 12 | } 13 | 14 | public static HandlerList getHandlerList() { 15 | return handlers; 16 | } 17 | 18 | private static final HandlerList handlers = new HandlerList(); 19 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/event/SpeechBystanderEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech.event; 2 | 3 | import net.citizensnpcs.api.ai.speech.SpeechContext; 4 | import net.citizensnpcs.api.ai.speech.Talkable; 5 | 6 | /** 7 | * Represents an event where a {@link Talkable} entity speaks by a {@link Talkable} bystander. 8 | * 9 | */ 10 | public class SpeechBystanderEvent extends SpeechEvent { 11 | public SpeechBystanderEvent(Talkable target, SpeechContext context, String message) { 12 | super(target, context, message); 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/SpeechController.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech; 2 | 3 | import net.citizensnpcs.api.npc.NPC; 4 | 5 | /** 6 | * Represents the NPCs speech abilities. Uses {@link SpeechContext}s which contain messages and recipients. 7 | * 8 | */ 9 | public interface SpeechController { 10 | /** 11 | * Sends the speechController's {@link NPC} and {@link SpeechContext}. 12 | * 13 | * @param message 14 | * The message to speak 15 | */ 16 | public void speak(SpeechContext message); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/HPAGraphEdge.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | public class HPAGraphEdge { 4 | final HPAGraphNode from; 5 | final HPAGraphNode to; 6 | final HPAGraphEdge.EdgeType type; 7 | final float weight; 8 | 9 | public HPAGraphEdge(HPAGraphNode from, HPAGraphNode to, HPAGraphEdge.EdgeType type, float weight) { 10 | this.from = from; 11 | this.to = to; 12 | this.type = type; 13 | this.weight = weight; 14 | } 15 | 16 | public enum EdgeType { 17 | INTER, 18 | INTRA; 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCreateEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | public class NPCCreateEvent extends NPCEvent { 8 | public NPCCreateEvent(NPC npc) { 9 | super(npc); 10 | } 11 | 12 | @Override 13 | public HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | private static final HandlerList handlers = new HandlerList(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCRemoveEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | public class NPCRemoveEvent extends NPCEvent { 8 | public NPCRemoveEvent(NPC npc) { 9 | super(npc); 10 | } 11 | 12 | @Override 13 | public HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | private static final HandlerList handlers = new HandlerList(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/ItemStackPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.bukkit.inventory.ItemStack; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | import net.citizensnpcs.api.util.ItemStorage; 7 | 8 | public class ItemStackPersister implements Persister { 9 | @Override 10 | public ItemStack create(DataKey root) { 11 | return ItemStorage.loadItemStack(root); 12 | } 13 | 14 | @Override 15 | public void save(ItemStack instance, DataKey root) { 16 | ItemStorage.saveItem(root, instance); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/InstantBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Marker interface for behaviors that execute instantly (in one tick). These behaviors complete immediately without 5 | * needing to return RUNNING. 6 | * 7 | * The parser will automatically coalesce consecutive instant behaviors into a single composite that executes them all 8 | * in one tick. 9 | */ 10 | public interface InstantBehavior extends Behavior { 11 | @Override 12 | default void reset() { 13 | } 14 | 15 | @Override 16 | default boolean shouldExecute() { 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/UUIDPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import java.util.UUID; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | 7 | public class UUIDPersister implements Persister { 8 | @Override 9 | public UUID create(DataKey root) { 10 | try { 11 | return UUID.fromString(root.getString("")); 12 | } catch (IllegalArgumentException e) { 13 | return null; 14 | } 15 | } 16 | 17 | @Override 18 | public void save(UUID instance, DataKey root) { 19 | root.setString("", instance.toString()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationCompleteEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | 7 | public class NavigationCompleteEvent extends NavigationEvent { 8 | public NavigationCompleteEvent(Navigator navigator) { 9 | super(navigator); 10 | } 11 | 12 | @Override 13 | public HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | private static final HandlerList handlers = new HandlerList(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/DelegatePersistence.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * Delegates persistence to a given {@link Persister}, which will be used to create and save instances. 10 | * 11 | * @see Persist 12 | * @see Persister 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ ElementType.CONSTRUCTOR, ElementType.FIELD }) 16 | public @interface DelegatePersistence { 17 | Class> value(); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/AttackStrategy.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import org.bukkit.entity.LivingEntity; 4 | 5 | public interface AttackStrategy { 6 | /** 7 | * Tries to attack the supplied target from the supplied attacker. Returns true if the attack was 8 | * handled, or false if the default attack strategy should be used. 9 | * 10 | * @param attacker 11 | * The entity attacker to use 12 | * @param target 13 | * The target to attack 14 | * @return Whether the attack was handled 15 | */ 16 | public boolean handle(LivingEntity attacker, LivingEntity target); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationBeginEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | 7 | public class NavigationBeginEvent extends NavigationEvent { 8 | public NavigationBeginEvent(Navigator navigator) { 9 | super(navigator); 10 | } 11 | 12 | @Override 13 | public HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | private static final HandlerList handlers = new HandlerList(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCAddTraitEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | import net.citizensnpcs.api.trait.Trait; 7 | 8 | public class NPCAddTraitEvent extends NPCTraitEvent { 9 | public NPCAddTraitEvent(NPC npc, Trait trait) { 10 | super(npc, trait); 11 | } 12 | 13 | @Override 14 | public HandlerList getHandlers() { 15 | return handlers; 16 | } 17 | 18 | public static HandlerList getHandlerList() { 19 | return handlers; 20 | } 21 | 22 | private static final HandlerList handlers = new HandlerList(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/VectorPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.bukkit.util.Vector; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | 7 | public class VectorPersister implements Persister { 8 | @Override 9 | public Vector create(DataKey root) { 10 | return new Vector(root.getDouble("x"), root.getDouble("y"), root.getDouble("z")); 11 | } 12 | 13 | @Override 14 | public void save(Vector instance, DataKey root) { 15 | root.setDouble("x", instance.getX()); 16 | root.setDouble("y", instance.getY()); 17 | root.setDouble("z", instance.getZ()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCRemoveTraitEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | import net.citizensnpcs.api.trait.Trait; 7 | 8 | public class NPCRemoveTraitEvent extends NPCTraitEvent { 9 | public NPCRemoveTraitEvent(NPC npc, Trait trait) { 10 | super(npc, trait); 11 | } 12 | 13 | @Override 14 | public HandlerList getHandlers() { 15 | return handlers; 16 | } 17 | 18 | public static HandlerList getHandlerList() { 19 | return handlers; 20 | } 21 | 22 | private static final HandlerList handlers = new HandlerList(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/BehaviorStatus.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | public enum BehaviorStatus { 4 | /** 5 | * Indicates that the {@link Behavior} has failed unrecoverably. 6 | */ 7 | FAILURE, 8 | /** 9 | * Indicates that the {@link Behavior} should be reset and removed by any parent {@link Composite} behavior nodes. 10 | */ 11 | RESET_AND_REMOVE, 12 | /** 13 | * Indicates that the {@link Behavior} is still running and should be continued next tick. 14 | */ 15 | RUNNING, 16 | /** 17 | * Indicates that the {@link Behavior} has succeeded and can be terminated. 18 | */ 19 | SUCCESS; 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import net.citizensnpcs.api.npc.NPC; 4 | 5 | /** 6 | * Represents an event thrown by an NPC. 7 | */ 8 | public abstract class NPCEvent extends CitizensEvent { 9 | final NPC npc; 10 | 11 | protected NPCEvent(NPC npc) { 12 | this.npc = npc; 13 | } 14 | 15 | protected NPCEvent(NPC npc, boolean async) { 16 | super(async); 17 | this.npc = npc; 18 | } 19 | 20 | /** 21 | * Get the npc involved in the event. 22 | * 23 | * @return the npc involved in the event 24 | */ 25 | public NPC getNPC() { 26 | return npc; 27 | } 28 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [fullwall] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/Storage.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util; 2 | 3 | public interface Storage { 4 | /** 5 | * Returns a {@link DataKey} starting from the given root. 6 | * 7 | * @param root 8 | * The root to start at 9 | * @return the created key 10 | */ 11 | public DataKey getKey(String root); 12 | 13 | /** 14 | * Loads data from a file or other location. 15 | * 16 | * @return Whether the load was successful 17 | */ 18 | public boolean load(); 19 | 20 | /** 21 | * Saves the in-memory aspects of the storage to disk. 22 | */ 23 | public void save(); 24 | 25 | public void saveAsync(); 26 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationReplaceEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | 7 | public class NavigationReplaceEvent extends NavigationCancelEvent { 8 | public NavigationReplaceEvent(Navigator navigator) { 9 | super(navigator, CancelReason.REPLACE); 10 | } 11 | 12 | @Override 13 | public HandlerList getHandlers() { 14 | return handlers; 15 | } 16 | 17 | public static HandlerList getHandlerList() { 18 | return handlers; 19 | } 20 | 21 | private static final HandlerList handlers = new HandlerList(); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/ClusterNode.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | public class ClusterNode extends ReversableAStarNode { 4 | int x, z; 5 | 6 | public ClusterNode(int x, int z) { 7 | this.x = x; 8 | this.z = z; 9 | } 10 | 11 | @Override 12 | public boolean equals(Object obj) { 13 | if (this == obj) 14 | return true; 15 | if (obj == null || getClass() != obj.getClass()) 16 | return false; 17 | ClusterNode other = (ClusterNode) obj; 18 | return x == other.x && z == other.z; 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | return 31 * (31 + x) + z; 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/Vector3fPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.joml.Vector3f; 4 | import org.joml.Vector3fc; 5 | 6 | import net.citizensnpcs.api.util.DataKey; 7 | 8 | public class Vector3fPersister implements Persister { 9 | @Override 10 | public Vector3fc create(DataKey root) { 11 | return new Vector3f().set(root.getDouble("0"), root.getDouble("1"), root.getDouble("2")); 12 | } 13 | 14 | @Override 15 | public void save(Vector3fc instance, DataKey root) { 16 | root.setDouble("0", instance.x()); 17 | root.setDouble("1", instance.y()); 18 | root.setDouble("2", instance.z()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/Requirements.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import org.bukkit.entity.EntityType; 7 | 8 | import net.citizensnpcs.api.trait.Trait; 9 | 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface Requirements { 12 | EntityType[] excludedTypes() default { EntityType.UNKNOWN }; 13 | 14 | boolean livingEntity() default false; 15 | 16 | boolean ownership() default false; 17 | 18 | boolean selected() default false; 19 | 20 | Class[] traits() default {}; 21 | 22 | EntityType[] types() default { EntityType.UNKNOWN }; 23 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/CommandUsageException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | public class CommandUsageException extends CommandException { 4 | private String usage; 5 | 6 | public CommandUsageException() { 7 | this(null, null); 8 | } 9 | 10 | public CommandUsageException(String message, String usage) { 11 | super(message); 12 | this.usage = usage; 13 | } 14 | 15 | public String getUsage() { 16 | return usage; 17 | } 18 | 19 | public void setUsage(String usage) { 20 | this.usage = usage; 21 | } 22 | 23 | private static final long serialVersionUID = -6761418114414516542L; 24 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCLeftClickEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | /** 9 | * Called when an NPC is left-clicked by a player. 10 | */ 11 | public class NPCLeftClickEvent extends NPCClickEvent { 12 | public NPCLeftClickEvent(NPC npc, Player clicker) { 13 | super(npc, clicker); 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public static HandlerList getHandlerList() { 22 | return handlers; 23 | } 24 | 25 | private static final HandlerList handlers = new HandlerList(); 26 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCloneEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | public class NPCCloneEvent extends NPCEvent { 8 | private final NPC clone; 9 | 10 | public NPCCloneEvent(NPC npc, NPC clone) { 11 | super(npc); 12 | this.clone = clone; 13 | } 14 | 15 | public NPC getClone() { 16 | return clone; 17 | } 18 | 19 | @Override 20 | public HandlerList getHandlers() { 21 | return handlers; 22 | } 23 | 24 | public static HandlerList getHandlerList() { 25 | return handlers; 26 | } 27 | 28 | private static final HandlerList handlers = new HandlerList(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/EulerAnglePersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.bukkit.util.EulerAngle; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | 7 | public class EulerAnglePersister implements Persister { 8 | @Override 9 | public EulerAngle create(DataKey root) { 10 | double x = root.getDouble("x"); 11 | double y = root.getDouble("y"); 12 | double z = root.getDouble("z"); 13 | return new EulerAngle(x, y, z); 14 | } 15 | 16 | @Override 17 | public void save(EulerAngle angle, DataKey root) { 18 | root.setDouble("x", angle.getX()); 19 | root.setDouble("y", angle.getY()); 20 | root.setDouble("z", angle.getZ()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/AStarSolution.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | 6 | import org.bukkit.util.Vector; 7 | 8 | import com.google.common.collect.Lists; 9 | 10 | public class AStarSolution { 11 | final float cost; 12 | private final List path; 13 | 14 | public AStarSolution(List path, float cost) { 15 | this.path = path; 16 | this.cost = cost; 17 | } 18 | 19 | public Collection convertToVectors() { 20 | return Lists.transform(path, input -> { 21 | HPAGraphNode node = ((HPAGraphAStarNode) input).node; 22 | return new Vector(node.x, node.y, node.z); 23 | }); 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/TraitEventHandler.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.util.function.Function; 8 | 9 | import org.bukkit.event.Event; 10 | import org.bukkit.event.EventHandler; 11 | 12 | import net.citizensnpcs.api.npc.NPC; 13 | 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.METHOD) 16 | public @interface TraitEventHandler { 17 | Class processor() default NPCEventExtractor.class; 18 | 19 | EventHandler value(); 20 | 21 | public interface NPCEventExtractor extends Function { 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/NMSHelper.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api; 2 | 3 | import org.bukkit.OfflinePlayer; 4 | import org.bukkit.command.BlockCommandSender; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.inventory.Inventory; 7 | import org.bukkit.inventory.meta.SkullMeta; 8 | 9 | import net.citizensnpcs.api.util.SpigotUtil.InventoryViewAPI; 10 | 11 | public interface NMSHelper { 12 | public OfflinePlayer getPlayer(BlockCommandSender sender); 13 | 14 | public String getTexture(SkullMeta meta); 15 | 16 | InventoryViewAPI openAnvilInventory(Player player, Inventory inventory, String title); 17 | 18 | public void setTexture(String string, SkullMeta meta); 19 | 20 | void updateInventoryTitle(Player player, InventoryViewAPI view, String newTitle); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/FlockBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.util.Vector; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * An interface to be used with an {@link Flocker} to represent a certain type of behavior such as cohesion, alignment 11 | * or separation. 12 | */ 13 | public interface FlockBehavior { 14 | /** 15 | * Returns the displacement vector to be combined with other {@link FlockBehavior} vectors by a {@link Flocker}. 16 | * 17 | * @param nearby 18 | * the set of NPCs to consider for flocking purposes 19 | * @return the displacement {@link Vector} 20 | */ 21 | Vector getVector(NPC npc, Collection nearby); 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/QuaternionfPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.joml.Quaternionf; 4 | import org.joml.Quaternionfc; 5 | 6 | import net.citizensnpcs.api.util.DataKey; 7 | 8 | public class QuaternionfPersister implements Persister { 9 | @Override 10 | public Quaternionfc create(DataKey root) { 11 | return new Quaternionf(root.getDouble("x"), root.getDouble("y"), root.getDouble("z"), root.getDouble("w")); 12 | } 13 | 14 | @Override 15 | public void save(Quaternionfc instance, DataKey root) { 16 | root.setDouble("x", instance.x()); 17 | root.setDouble("y", instance.y()); 18 | root.setDouble("z", instance.z()); 19 | root.setDouble("w", instance.w()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/NamespacedKeyPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.bukkit.NamespacedKey; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | import net.citizensnpcs.api.util.SpigotUtil; 7 | 8 | public class NamespacedKeyPersister implements Persister { 9 | @Override 10 | public NamespacedKey create(DataKey root) { 11 | String val = root.getString(""); 12 | if (val == null || val.isEmpty() || val.equals("minecraft:")) 13 | return null; 14 | return SpigotUtil.getKey(root.getString("")); 15 | } 16 | 17 | @Override 18 | public void save(NamespacedKey instance, DataKey root) { 19 | root.setString("", instance.getNamespace() + ":" + instance.getKey()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.Event; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public abstract class NavigationEvent extends Event { 9 | private final Navigator navigator; 10 | 11 | protected NavigationEvent(Navigator navigator) { 12 | this.navigator = navigator; 13 | } 14 | 15 | /** 16 | * @return The {@link Navigator} involved in this event 17 | */ 18 | public Navigator getNavigator() { 19 | return navigator; 20 | } 21 | 22 | /** 23 | * @return The {@link NPC} involved in this event 24 | */ 25 | public NPC getNPC() { 26 | return navigator.getNPC(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/exception/CommandException.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command.exception; 2 | 3 | import net.citizensnpcs.api.util.Messaging; 4 | 5 | public class CommandException extends Exception { 6 | public CommandException() { 7 | } 8 | 9 | public CommandException(String message) { 10 | super(Messaging.tryTranslate(message)); 11 | } 12 | 13 | public CommandException(String key, Object... replacements) { 14 | super(Messaging.tr(key, replacements)); 15 | } 16 | 17 | public CommandException(Throwable t) { 18 | super(t); 19 | } 20 | 21 | @Override 22 | public Throwable fillInStackTrace() { 23 | return this; 24 | } 25 | 26 | private static final long serialVersionUID = 870638193072101739L; 27 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/ParallelComposite.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * A composite that runs all parallel children. Returns SUCCESS when all parallel children complete. Individual child 7 | * status doesn't affect the composite's return value. 8 | */ 9 | public class ParallelComposite extends Composite { 10 | public ParallelComposite(Collection behaviors) { 11 | super(behaviors); 12 | } 13 | 14 | @Override 15 | public BehaviorStatus run() { 16 | if (parallelExecuting.isEmpty()) 17 | return BehaviorStatus.SUCCESS; 18 | tickParallel(); 19 | return BehaviorStatus.RUNNING; 20 | } 21 | 22 | @Override 23 | public boolean shouldExecute() { 24 | return true; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCUnlinkFromPlayerEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCUnlinkFromPlayerEvent extends NPCEvent { 9 | private final Player player; 10 | 11 | public NPCUnlinkFromPlayerEvent(NPC npc, Player player) { 12 | super(npc); 13 | this.player = player; 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public Player getPlayer() { 22 | return player; 23 | } 24 | 25 | public static HandlerList getHandlerList() { 26 | return handlers; 27 | } 28 | 29 | private static final HandlerList handlers = new HandlerList(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/templates/TemplateWorkspace.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc.templates; 2 | 3 | import java.io.File; 4 | 5 | import net.citizensnpcs.api.CitizensAPI; 6 | 7 | public class TemplateWorkspace { 8 | private final File citizensFolder; 9 | private final File namespaceFolder; 10 | private final File templatesFolder; 11 | 12 | public TemplateWorkspace(File namespaceFolder) { 13 | this.namespaceFolder = namespaceFolder; 14 | this.citizensFolder = CitizensAPI.getDataFolder(); 15 | this.templatesFolder = new File(citizensFolder, "templates"); 16 | } 17 | 18 | public File getFile(String fileName) { 19 | File test = new File(namespaceFolder, fileName); 20 | return test.exists() && test.getParentFile().equals(namespaceFolder) ? test : null; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCLinkToPlayerEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCLinkToPlayerEvent extends NPCEvent { 9 | private final Player player; 10 | 11 | public NPCLinkToPlayerEvent(NPC npc, Player player, boolean async) { 12 | super(npc, async); 13 | this.player = player; 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public Player getPlayer() { 22 | return player; 23 | } 24 | 25 | public static HandlerList getHandlerList() { 26 | return handlers; 27 | } 28 | 29 | private static final HandlerList handlers = new HandlerList(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CommandSenderCloneNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class CommandSenderCloneNPCEvent extends CommandSenderCreateNPCEvent { 9 | private final NPC npc; 10 | 11 | public CommandSenderCloneNPCEvent(CommandSender sender, NPC npc, NPC copy) { 12 | super(sender, copy); 13 | this.npc = npc; 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public NPC getOriginal() { 22 | return npc; 23 | } 24 | 25 | public static HandlerList getHandlerList() { 26 | return handlers; 27 | } 28 | 29 | private static final HandlerList handlers = new HandlerList(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/ReversableAStarNode.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class ReversableAStarNode implements Comparable { 8 | float g; 9 | float h; 10 | ReversableAStarNode parent; 11 | 12 | @Override 13 | public int compareTo(ReversableAStarNode o) { 14 | return Float.compare(g + h, o.g + o.h); 15 | } 16 | 17 | public List reconstructSolution() { 18 | List parents = new ArrayList<>(); 19 | ReversableAStarNode start = this; 20 | while (start != null) { 21 | parents.add(start); 22 | start = start.parent; 23 | } 24 | Collections.reverse(parents); 25 | return parents; 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/AbstractPathStrategy.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import net.citizensnpcs.api.ai.event.CancelReason; 4 | 5 | public abstract class AbstractPathStrategy implements PathStrategy { 6 | private CancelReason cancelReason; 7 | private final TargetType type; 8 | 9 | protected AbstractPathStrategy(TargetType type) { 10 | this.type = type; 11 | } 12 | 13 | @Override 14 | public void clearCancelReason() { 15 | cancelReason = null; 16 | } 17 | 18 | @Override 19 | public CancelReason getCancelReason() { 20 | return cancelReason; 21 | } 22 | 23 | @Override 24 | public TargetType getTargetType() { 25 | return type; 26 | } 27 | 28 | protected void setCancelReason(CancelReason reason) { 29 | cancelReason = reason; 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/Flag.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import net.citizensnpcs.api.command.Arg.CompletionsProvider; 9 | import net.citizensnpcs.api.command.Arg.FlagValidator; 10 | 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target(ElementType.PARAMETER) 13 | public @interface Flag { 14 | String[] completions() default {}; 15 | 16 | Class completionsProvider() default CompletionsProvider.Identity.class; 17 | 18 | String defValue() default ""; 19 | 20 | String permission() default ""; 21 | 22 | Class> validator() default FlagValidator.Identity.class; 23 | 24 | String[] value(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCRemoveByCommandSenderEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCRemoveByCommandSenderEvent extends NPCRemoveEvent { 9 | private final CommandSender source; 10 | 11 | public NPCRemoveByCommandSenderEvent(NPC npc, CommandSender source) { 12 | super(npc); 13 | this.source = source; 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public CommandSender getSource() { 22 | return source; 23 | } 24 | 25 | public static HandlerList getHandlerList() { 26 | return handlers; 27 | } 28 | 29 | private static final HandlerList handlers = new HandlerList(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/ComponentPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import com.google.common.io.BaseEncoding; 4 | 5 | import net.citizensnpcs.api.util.DataKey; 6 | import net.kyori.adventure.text.Component; 7 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 8 | 9 | public class ComponentPersister implements Persister { 10 | @Override 11 | public Component create(DataKey root) { 12 | String component = root.getString(""); 13 | return GsonComponentSerializer.gson().deserialize(new String(BaseEncoding.base64().decode(component))); 14 | } 15 | 16 | @Override 17 | public void save(Component text, DataKey root) { 18 | String output = GsonComponentSerializer.gson().serialize(text); 19 | root.setString("", BaseEncoding.base64().encode(output.getBytes())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDamageByBlockEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityDamageByBlockEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCDamageByBlockEvent extends NPCDamageEvent { 10 | private final Block damager; 11 | 12 | public NPCDamageByBlockEvent(NPC npc, EntityDamageByBlockEvent event) { 13 | super(npc, event); 14 | damager = event.getDamager(); 15 | } 16 | 17 | public Block getDamager() { 18 | return damager; 19 | } 20 | 21 | @Override 22 | public HandlerList getHandlers() { 23 | return handlers; 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return handlers; 28 | } 29 | 30 | private static final HandlerList handlers = new HandlerList(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDamageEntityEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCDamageEntityEvent extends NPCDamageEvent { 10 | private final Entity damaged; 11 | 12 | public NPCDamageEntityEvent(NPC npc, EntityDamageByEntityEvent event) { 13 | super(npc, event); 14 | damaged = event.getEntity(); 15 | } 16 | 17 | public Entity getDamaged() { 18 | return damaged; 19 | } 20 | 21 | @Override 22 | public HandlerList getHandlers() { 23 | return handlers; 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return handlers; 28 | } 29 | 30 | private static final HandlerList handlers = new HandlerList(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCPistonPushEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCPistonPushEvent extends NPCEvent implements Cancellable { 9 | private boolean cancelled; 10 | 11 | public NPCPistonPushEvent(NPC npc) { 12 | super(npc); 13 | } 14 | 15 | @Override 16 | public HandlerList getHandlers() { 17 | return handlers; 18 | } 19 | 20 | @Override 21 | public boolean isCancelled() { 22 | return cancelled; 23 | } 24 | 25 | @Override 26 | public void setCancelled(boolean arg0) { 27 | cancelled = arg0; 28 | } 29 | 30 | public static HandlerList getHandlerList() { 31 | return handlers; 32 | } 33 | 34 | private static final HandlerList handlers = new HandlerList(); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/InventoryMenuPage.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import org.bukkit.entity.HumanEntity; 4 | import org.bukkit.event.inventory.InventoryClickEvent; 5 | import org.bukkit.inventory.Inventory; 6 | 7 | /** 8 | * The concrete page instance representing a single page in a stack of inventory menu GUIs. Injected variables will be 9 | * available after {@link #initialise(MenuContext)} is called. 10 | * 11 | * @see InventoryMenu 12 | */ 13 | public abstract class InventoryMenuPage implements Runnable { 14 | public Inventory createInventory(String title) { 15 | return null; 16 | } 17 | 18 | public abstract void initialise(MenuContext ctx); 19 | 20 | public void onClick(InventoryMenuSlot slot, InventoryClickEvent event) { 21 | } 22 | 23 | public void onClose(HumanEntity player) { 24 | } 25 | 26 | @Override 27 | public void run() { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/InventoryMenuTransition.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | /** 4 | * The concrete class of {@link MenuTransition}. Defines a transition from one {@link InventoryMenuPage} to another when 5 | * clicked. 6 | */ 7 | public class InventoryMenuTransition { 8 | private final InventoryMenuSlot slot; 9 | private final Class transition; 10 | 11 | public InventoryMenuTransition(InventoryMenuSlot slot, Class transition) { 12 | this.slot = slot; 13 | this.transition = transition; 14 | } 15 | 16 | Class accept(InventoryMenuSlot accept) { 17 | return accept.equals(slot) ? transition : null; 18 | } 19 | 20 | /** 21 | * @return The slot holding the transition 22 | */ 23 | public InventoryMenuSlot getSlot() { 24 | return slot; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/Persister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import net.citizensnpcs.api.util.DataKey; 4 | 5 | /** 6 | * A serialisation primitive to be used with {@link PersistenceLoader} to serialise custom objects. 7 | */ 8 | public interface Persister { 9 | /** 10 | * Creates an object instance from the given {@link DataKey}. Should not return null unless no data is present. 11 | * 12 | * @param root 13 | * The root key to load from 14 | * @return The created instance, or null if no data was present 15 | */ 16 | T create(DataKey root); 17 | 18 | /** 19 | * Saves the object instance to the given {@link DataKey}. 20 | * 21 | * @param instance 22 | * The object instance to save 23 | * @param root 24 | * The key to save into 25 | */ 26 | void save(T instance, DataKey root); 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationCancelEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | 7 | public class NavigationCancelEvent extends NavigationCompleteEvent { 8 | private final CancelReason reason; 9 | 10 | public NavigationCancelEvent(Navigator navigator, CancelReason reason) { 11 | super(navigator); 12 | this.reason = reason; 13 | } 14 | 15 | /** 16 | * @return The cancellation reason 17 | */ 18 | public CancelReason getCancelReason() { 19 | return reason; 20 | } 21 | 22 | @Override 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | 27 | public static HandlerList getHandlerList() { 28 | return handlers; 29 | } 30 | 31 | private static final HandlerList handlers = new HandlerList(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/PlayerCreateNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class PlayerCreateNPCEvent extends CommandSenderCreateNPCEvent implements Cancellable { 10 | public PlayerCreateNPCEvent(Player player, NPC npc) { 11 | super(player, npc); 12 | } 13 | 14 | /** 15 | * @return The {@link Player} creating the NPC. 16 | */ 17 | @Override 18 | public Player getCreator() { 19 | return (Player) super.getCreator(); 20 | } 21 | 22 | @Override 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | 27 | public static HandlerList getHandlerList() { 28 | return handlers; 29 | } 30 | 31 | private static final HandlerList handlers = new HandlerList(); 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/MemoryNPCDataStore.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc; 2 | 3 | public class MemoryNPCDataStore implements NPCDataStore { 4 | private int lastID; 5 | 6 | @Override 7 | public void clearData(NPC npc) { 8 | } 9 | 10 | @Override 11 | public void clearTraitData(Iterable traitNames) { 12 | } 13 | 14 | @Override 15 | public int createUniqueNPCId(NPCRegistry registry) { 16 | return lastID++; 17 | } 18 | 19 | @Override 20 | public void loadInto(NPCRegistry registry) { 21 | } 22 | 23 | @Override 24 | public void reloadFromSource() { 25 | } 26 | 27 | @Override 28 | public void saveToDisk() { 29 | } 30 | 31 | @Override 32 | public void saveToDiskImmediate() { 33 | } 34 | 35 | @Override 36 | public void store(NPC npc) { 37 | } 38 | 39 | @Override 40 | public void storeAll(NPCRegistry registry) { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/ParallelBehaviorWrapper.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Wraps a behavior to run in parallel with other behaviors. 5 | * Implements ParallelBehavior marker interface to signal to composite parents 6 | * that this behavior should run alongside others. 7 | */ 8 | public class ParallelBehaviorWrapper implements Behavior, ParallelBehavior { 9 | private final Behavior wrapped; 10 | 11 | public ParallelBehaviorWrapper(Behavior wrapped) { 12 | this.wrapped = wrapped; 13 | } 14 | 15 | @Override 16 | public void reset() { 17 | wrapped.reset(); 18 | } 19 | 20 | @Override 21 | public BehaviorStatus run() { 22 | return wrapped.run(); 23 | } 24 | 25 | @Override 26 | public boolean shouldExecute() { 27 | return wrapped.shouldExecute(); 28 | } 29 | 30 | public Behavior getWrapped() { 31 | return wrapped; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDamageByEntityEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCDamageByEntityEvent extends NPCDamageEvent { 10 | private final Entity damager; 11 | 12 | public NPCDamageByEntityEvent(NPC npc, EntityDamageByEntityEvent event) { 13 | super(npc, event); 14 | damager = event.getDamager(); 15 | } 16 | 17 | public Entity getDamager() { 18 | return damager; 19 | } 20 | 21 | @Override 22 | public HandlerList getHandlers() { 23 | return handlers; 24 | } 25 | 26 | public static HandlerList getHandlerList() { 27 | return handlers; 28 | } 29 | 30 | private static final HandlerList handlers = new HandlerList(); 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCollisionEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCCollisionEvent extends NPCEvent { 9 | private final Entity entity; 10 | 11 | public NPCCollisionEvent(NPC npc, Entity entity) { 12 | super(npc); 13 | this.entity = entity; 14 | } 15 | 16 | /** 17 | * Returns the {@link Entity} that collided with the {@link NPC}. 18 | * 19 | * @return The collided entity 20 | */ 21 | public Entity getCollidedWith() { 22 | return entity; 23 | } 24 | 25 | @Override 26 | public HandlerList getHandlers() { 27 | return handlers; 28 | } 29 | 30 | public static HandlerList getHandlerList() { 31 | return handlers; 32 | } 33 | 34 | private static final HandlerList handlers = new HandlerList(); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensSerialiseMetaEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | import org.bukkit.inventory.meta.ItemMeta; 5 | 6 | import net.citizensnpcs.api.util.DataKey; 7 | 8 | public class CitizensSerialiseMetaEvent extends CitizensEvent { 9 | private final DataKey key; 10 | private final ItemMeta meta; 11 | 12 | public CitizensSerialiseMetaEvent(DataKey key, ItemMeta meta) { 13 | this.key = key; 14 | this.meta = meta; 15 | } 16 | 17 | @Override 18 | public HandlerList getHandlers() { 19 | return handlers; 20 | } 21 | 22 | public DataKey getKey() { 23 | return key; 24 | } 25 | 26 | public ItemMeta getMeta() { 27 | return meta; 28 | } 29 | 30 | public static HandlerList getHandlerList() { 31 | return handlers; 32 | } 33 | 34 | private static final HandlerList handlers = new HandlerList(); 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/event/NavigationStuckEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.ai.Navigator; 6 | import net.citizensnpcs.api.ai.StuckAction; 7 | 8 | public class NavigationStuckEvent extends NavigationEvent { 9 | private StuckAction action; 10 | 11 | public NavigationStuckEvent(Navigator navigator, StuckAction action) { 12 | super(navigator); 13 | this.action = action; 14 | } 15 | 16 | public StuckAction getAction() { 17 | return action; 18 | } 19 | 20 | @Override 21 | public HandlerList getHandlers() { 22 | return handlers; 23 | } 24 | 25 | public void setAction(StuckAction action) { 26 | this.action = action; 27 | } 28 | 29 | public static HandlerList getHandlerList() { 30 | return handlers; 31 | } 32 | 33 | private static final HandlerList handlers = new HandlerList(); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/InverterDecorator.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Decorator that inverts SUCCESS to FAILURE and vice versa. 5 | */ 6 | public class InverterDecorator implements Behavior { 7 | private final Behavior child; 8 | 9 | public InverterDecorator(Behavior child) { 10 | this.child = child; 11 | } 12 | 13 | @Override 14 | public void reset() { 15 | child.reset(); 16 | } 17 | 18 | @Override 19 | public BehaviorStatus run() { 20 | BehaviorStatus status = child.run(); 21 | switch (status) { 22 | case SUCCESS: 23 | return BehaviorStatus.FAILURE; 24 | case FAILURE: 25 | return BehaviorStatus.SUCCESS; 26 | default: 27 | return status; 28 | } 29 | } 30 | 31 | @Override 32 | public boolean shouldExecute() { 33 | return child.shouldExecute(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuPattern.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Repeatable; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | /** 10 | * Defines a pattern of slots and/or transitions. Can be linked to a {@link InventoryMenuPattern} or simply at the class 11 | * level. 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 15 | @Repeatable(MenuPatterns.class) 16 | public @interface MenuPattern { 17 | /** 18 | * The offset position to start the pattern at. 19 | */ 20 | int[] offset(); 21 | 22 | MenuSlot[] slots() default {}; 23 | 24 | MenuTransition[] transitions() default {}; 25 | 26 | /** 27 | * The pattern string. 0 = AIR 28 | */ 29 | String value(); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCRightClickEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | /** 9 | * Called when an NPC is right-clicked by a player. 10 | */ 11 | public class NPCRightClickEvent extends NPCClickEvent { 12 | private boolean toCancel; 13 | 14 | public NPCRightClickEvent(NPC npc, Player click) { 15 | super(npc, click); 16 | } 17 | 18 | @Override 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public boolean isDelayedCancellation() { 24 | return toCancel; 25 | } 26 | 27 | public void setDelayedCancellation(boolean toCancel) { 28 | this.toCancel = true; 29 | } 30 | 31 | public static HandlerList getHandlerList() { 32 | return handlers; 33 | } 34 | 35 | private static final HandlerList handlers = new HandlerList(); 36 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/GoalSelector.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | public interface GoalSelector { 4 | /** 5 | * Stops executing any currently running {@link Goal}s and allows other goals to be selected for execution. 6 | */ 7 | void finish(); 8 | 9 | /** 10 | * Calls {@link #finish()} and removes the {@link Goal} from the list of possible goals to execute. 11 | */ 12 | void finishAndRemove(); 13 | 14 | /** 15 | * Replaces the execution of any running {@link Goal}s with the specified goal. 16 | * 17 | * @param goal 18 | * The new goal for execution 19 | */ 20 | void select(Goal goal); 21 | 22 | /** 23 | * Adds the provided {@link Goal}s to the execution list. These goals will be executed along with any previously 24 | * running goals. 25 | * 26 | * @param goals 27 | * The additional goals 28 | */ 29 | void selectAdditional(Goal... goals); 30 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/HPAGraphAStarNode.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | public class HPAGraphAStarNode extends ReversableAStarNode { 4 | private final HPAGraphEdge edge; 5 | final HPAGraphNode node; 6 | 7 | public HPAGraphAStarNode(HPAGraphNode node, HPAGraphEdge edge) { 8 | this.node = node; 9 | this.edge = edge; 10 | } 11 | 12 | @Override 13 | public boolean equals(Object obj) { 14 | if (this == obj) 15 | return true; 16 | if (obj == null || getClass() != obj.getClass()) 17 | return false; 18 | HPAGraphAStarNode other = (HPAGraphAStarNode) obj; 19 | return node.x == other.node.x && node.z == other.node.z; 20 | } 21 | 22 | @Override 23 | public int hashCode() { 24 | return 31 * (31 + node.x) + node.z; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return (edge != null ? edge.from.toString() : "") + "->" + node.toString(); 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/schedulers/adapter/SpigotSchedulerTask.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util.schedulers.adapter; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | import org.bukkit.scheduler.BukkitTask; 5 | 6 | import net.citizensnpcs.api.util.schedulers.SchedulerTask; 7 | 8 | public class SpigotSchedulerTask implements SchedulerTask { 9 | private final BukkitTask task; 10 | 11 | public SpigotSchedulerTask(BukkitTask task) { 12 | this.task = task; 13 | } 14 | 15 | @Override 16 | public void cancel() { 17 | task.cancel(); 18 | } 19 | 20 | @Override 21 | public BukkitTask getOriginalTask() { 22 | return task; 23 | } 24 | 25 | @Override 26 | public Plugin getPlugin() { 27 | return task.getOwner(); 28 | } 29 | 30 | @Override 31 | public boolean isCancelled() { 32 | return task.isCancelled(); 33 | } 34 | 35 | @Override 36 | public boolean isRepeating() { 37 | return false; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/Goal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | /** 4 | * Represents a Goal that can be added to a {@link GoalController}. 5 | *

6 | * A Goal represents an abstract node in a tree of events. It can be anything from attacking players to a villager. By 7 | * using the {@link GoalSelector} provided in {@link #shouldExecute(GoalSelector)} the Goal can traverse its tree of 8 | * behaviours. 9 | */ 10 | public interface Goal { 11 | /** 12 | * Resets the goal and any resources or state it is holding. 13 | */ 14 | public void reset(); 15 | 16 | /** 17 | * Updates the goal. 18 | */ 19 | public void run(GoalSelector selector); 20 | 21 | /** 22 | * Returns whether the goal is ready to start. 23 | * 24 | * @param selector 25 | * The selector to use during execution 26 | * @return Whether the goal can be started. 27 | */ 28 | public boolean shouldExecute(GoalSelector selector); 29 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/BehaviorGoalAdapter.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import net.citizensnpcs.api.ai.Goal; 4 | import net.citizensnpcs.api.ai.GoalSelector; 5 | 6 | /** 7 | * An adapter between {@link Goal} and {@link Behavior}, forwarding the calls correctly between them. 8 | */ 9 | public abstract class BehaviorGoalAdapter implements Goal, Behavior { 10 | @Override 11 | public void run(GoalSelector selector) { 12 | BehaviorStatus status = run(); 13 | if (status == BehaviorStatus.RESET_AND_REMOVE) { 14 | selector.finishAndRemove(); 15 | } else if (status == BehaviorStatus.FAILURE || status == BehaviorStatus.SUCCESS) { 16 | selector.finish(); 17 | } 18 | } 19 | 20 | @Override 21 | public boolean shouldExecute(GoalSelector selector) { 22 | return shouldExecute(); 23 | } 24 | 25 | public static Goal create(Behavior behavior) { 26 | return new ForwardingBehaviorGoalAdapter(behavior); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensDeserialiseMetaEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.inventory.ItemStack; 6 | 7 | import net.citizensnpcs.api.util.DataKey; 8 | 9 | public class CitizensDeserialiseMetaEvent extends Event { 10 | private final ItemStack itemstack; 11 | private final DataKey key; 12 | 13 | public CitizensDeserialiseMetaEvent(DataKey key, ItemStack itemstack) { 14 | this.key = key; 15 | this.itemstack = itemstack; 16 | } 17 | 18 | @Override 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public ItemStack getItemStack() { 24 | return itemstack; 25 | } 26 | 27 | public DataKey getKey() { 28 | return key; 29 | } 30 | 31 | public static HandlerList getHandlerList() { 32 | return handlers; 33 | } 34 | 35 | private static final HandlerList handlers = new HandlerList(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCSelectEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | /** 9 | * Called when an NPC is selected by a player. 10 | */ 11 | public class NPCSelectEvent extends NPCEvent { 12 | private final CommandSender sender; 13 | 14 | public NPCSelectEvent(NPC npc, CommandSender sender) { 15 | super(npc); 16 | this.sender = sender; 17 | } 18 | 19 | @Override 20 | public HandlerList getHandlers() { 21 | return handlers; 22 | } 23 | 24 | /** 25 | * Gets the selector of the NPC. 26 | * 27 | * @return CommandSender that selected an NPC 28 | */ 29 | public CommandSender getSelector() { 30 | return sender; 31 | } 32 | 33 | public static HandlerList getHandlerList() { 34 | return handlers; 35 | } 36 | 37 | private static final HandlerList handlers = new HandlerList(); 38 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/expr/ExpressionEngine.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.expr; 2 | 3 | /** 4 | * Expression evaluation abstraction (e.g., Molang, JavaScript, Denizen). 5 | */ 6 | public interface ExpressionEngine { 7 | /** 8 | * Compiles an expression string into a reusable compiled form. 9 | * 10 | * @param expression 11 | * the expression text 12 | * @return a compiled expression that can be evaluated multiple times 13 | */ 14 | CompiledExpression compile(String expression) throws ExpressionCompileException; 15 | 16 | String getName(); 17 | 18 | public static class ExpressionCompileException extends Exception { 19 | public ExpressionCompileException(String message) { 20 | super(message); 21 | } 22 | 23 | public ExpressionCompileException(String message, Throwable cause) { 24 | super(message, cause); 25 | } 26 | 27 | private static final long serialVersionUID = 1716686092053880737L; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCRenameEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | public class NPCRenameEvent extends NPCEvent { 8 | private String newName; 9 | private final String oldName; 10 | 11 | public NPCRenameEvent(NPC npc, String oldName, String newName) { 12 | super(npc); 13 | this.oldName = oldName; 14 | this.setNewName(newName); 15 | } 16 | 17 | @Override 18 | public HandlerList getHandlers() { 19 | return handlers; 20 | } 21 | 22 | public String getNewName() { 23 | return newName; 24 | } 25 | 26 | public String getOldName() { 27 | return oldName; 28 | } 29 | 30 | public void setNewName(String newName) { 31 | this.newName = newName; 32 | } 33 | 34 | public static HandlerList getHandlerList() { 35 | return handlers; 36 | } 37 | 38 | private static final HandlerList handlers = new HandlerList(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CitizensGetSelectedNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class CitizensGetSelectedNPCEvent extends CitizensEvent { 9 | private NPC selected; 10 | private final CommandSender sender; 11 | 12 | public CitizensGetSelectedNPCEvent(CommandSender sender) { 13 | this.sender = sender; 14 | } 15 | 16 | @Override 17 | public HandlerList getHandlers() { 18 | return handlers; 19 | } 20 | 21 | public NPC getSelected() { 22 | return selected; 23 | } 24 | 25 | public CommandSender getSender() { 26 | return sender; 27 | } 28 | 29 | public void setSelected(NPC npc) { 30 | this.selected = npc; 31 | } 32 | 33 | public static HandlerList getHandlerList() { 34 | return handlers; 35 | } 36 | 37 | private static final HandlerList handlers = new HandlerList(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/ClickHandler.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Repeatable; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import org.bukkit.event.inventory.InventoryAction; 10 | import org.bukkit.event.inventory.InventoryClickEvent; 11 | 12 | /** 13 | * Annotates a method as a click handler that will accept inventory click events. Currently, each listener must take 14 | * {@link InventoryMenuSlot} and {@link InventoryClickEvent} arguments. 15 | */ 16 | @Retention(RetentionPolicy.RUNTIME) 17 | @Target({ ElementType.METHOD }) 18 | @Repeatable(ClickHandlers.class) 19 | public @interface ClickHandler { 20 | /** 21 | * An optional filter for specific actions. Default = handle all clicks 22 | */ 23 | InventoryAction[] filter() default {}; 24 | 25 | /** 26 | * The slot position to handle clicks for. 27 | */ 28 | int[] slot(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/CommandAnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command; 2 | 3 | import java.lang.annotation.Annotation; 4 | 5 | import org.bukkit.command.CommandSender; 6 | 7 | import net.citizensnpcs.api.command.exception.CommandException; 8 | 9 | public interface CommandAnnotationProcessor { 10 | /** 11 | * @return The {@link Annotation} class that this processor will accept. 12 | */ 13 | Class getAnnotationClass(); 14 | 15 | /** 16 | * @param sender 17 | * The command sender 18 | * @param context 19 | * The context of the command, including arguments 20 | * @param instance 21 | * The {@link Annotation} instance 22 | * @param args 23 | * The method arguments 24 | * @throws CommandException 25 | * If an exception occurs 26 | */ 27 | void process(CommandSender sender, CommandContext context, Annotation instance, Object[] args) 28 | throws CommandException; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/schedulers/adapter/FoliaSchedulerTask.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util.schedulers.adapter; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | 5 | import io.papermc.paper.threadedregions.scheduler.ScheduledTask; 6 | import net.citizensnpcs.api.util.schedulers.SchedulerTask; 7 | 8 | public class FoliaSchedulerTask implements SchedulerTask { 9 | private final ScheduledTask task; 10 | 11 | public FoliaSchedulerTask(ScheduledTask task) { 12 | this.task = task; 13 | } 14 | 15 | @Override 16 | public void cancel() { 17 | task.cancel(); 18 | } 19 | 20 | @Override 21 | public ScheduledTask getOriginalTask() { 22 | return task; 23 | } 24 | 25 | @Override 26 | public Plugin getPlugin() { 27 | return task.getOwningPlugin(); 28 | } 29 | 30 | @Override 31 | public boolean isCancelled() { 32 | return task.isCancelled(); 33 | } 34 | 35 | @Override 36 | public boolean isRepeating() { 37 | return task.isRepeatingTask(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/Menu.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import org.bukkit.event.inventory.ClickType; 9 | import org.bukkit.event.inventory.InventoryType; 10 | 11 | /** 12 | * Defines a GUI inventory menu. Can be linked to a {@link InventoryMenuPattern} or simply at the class level. 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ ElementType.TYPE }) 16 | public @interface Menu { 17 | /** 18 | * The dimensions of the menu, if supported. 19 | */ 20 | int[] dimensions() default { 3, 3 }; 21 | 22 | /** 23 | * The click types to allow by default. Empty = all allowed 24 | */ 25 | ClickType[] filter() default {}; 26 | 27 | /** 28 | * The menu title. 29 | */ 30 | String title() default ""; 31 | 32 | /** 33 | * The inventory type. 34 | */ 35 | InventoryType type() default InventoryType.CHEST; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/AStarStorage.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | /** 4 | * The storage for an {@link AStarMachine}. Controls the open and closed sets. 5 | */ 6 | public interface AStarStorage { 7 | /** 8 | * Close a given {@link AStarNode}, moving it from the open set to the closed set. 9 | */ 10 | void close(AStarNode node); 11 | 12 | /** 13 | * @return The {@link AStarNode} to examine next from the frontier 14 | */ 15 | AStarNode getBestNode(); 16 | 17 | /** 18 | * Close a given {@link AStarNode}, moving or adding it from the frontier to the open set. 19 | */ 20 | void open(AStarNode node); 21 | 22 | /** 23 | * Returns the best node from the frontier and removes it. 24 | * 25 | * @return The {@link AStarNode} to examine next from the frontier 26 | */ 27 | AStarNode removeBestNode(); 28 | 29 | /** 30 | * Returns whether to examine a given {@link AStarNode}. 31 | */ 32 | boolean shouldExamine(AStarNode neighbour); 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/PlayerCloneNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class PlayerCloneNPCEvent extends PlayerCreateNPCEvent implements Cancellable { 10 | private final NPC npc; 11 | 12 | public PlayerCloneNPCEvent(Player player, NPC npc, NPC copy) { 13 | super(player, copy); 14 | this.npc = npc; 15 | } 16 | 17 | /** 18 | * @return The {@link Player} creating the NPC. 19 | */ 20 | @Override 21 | public Player getCreator() { 22 | return super.getCreator(); 23 | } 24 | 25 | @Override 26 | public HandlerList getHandlers() { 27 | return handlers; 28 | } 29 | 30 | public NPC getOriginal() { 31 | return npc; 32 | } 33 | 34 | public static HandlerList getHandlerList() { 35 | return handlers; 36 | } 37 | 38 | private static final HandlerList handlers = new HandlerList(); 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/BlockSource.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.block.data.BlockData; 5 | import org.bukkit.util.Vector; 6 | 7 | import net.citizensnpcs.api.util.BoundingBox; 8 | 9 | public abstract class BlockSource { 10 | public abstract BlockData getBlockDataAt(int x, int y, int z); 11 | 12 | public BlockData getBlockDataAt(Vector position) { 13 | return getBlockDataAt(position.getBlockX(), position.getBlockY(), position.getBlockZ()); 14 | } 15 | 16 | public abstract BoundingBox getCollisionBox(int x, int y, int z); 17 | 18 | public BoundingBox getCollisionBox(Vector pos) { 19 | return getCollisionBox(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); 20 | } 21 | 22 | public abstract Material getMaterialAt(int x, int y, int z); 23 | 24 | public Material getMaterialAt(Vector pos) { 25 | return getMaterialAt(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); 26 | } 27 | 28 | public abstract boolean isYWithinBounds(int y); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCLookCloseChangeTargetEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | public class NPCLookCloseChangeTargetEvent extends NPCEvent { 9 | private Player next; 10 | private final Player old; 11 | 12 | public NPCLookCloseChangeTargetEvent(NPC npc, Player old, Player next) { 13 | super(npc); 14 | this.old = old; 15 | this.next = next; 16 | } 17 | 18 | @Override 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public Player getNewTarget() { 24 | return next; 25 | } 26 | 27 | public Player getPreviousTarget() { 28 | return old; 29 | } 30 | 31 | public void setNewTarget(Player target) { 32 | this.next = target; 33 | } 34 | 35 | public static HandlerList getHandlerList() { 36 | return handlers; 37 | } 38 | 39 | private static final HandlerList handlers = new HandlerList(); 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/PermissionUtil.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util; 2 | 3 | import java.util.Collection; 4 | import java.util.Set; 5 | 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.entity.Player; 8 | 9 | import net.milkbowl.vault.permission.Permission; 10 | 11 | public class PermissionUtil { 12 | public static boolean hasPermission(Set permissions, Player player) { 13 | return permissions.stream().anyMatch(permission -> player.hasPermission(permission)); 14 | } 15 | 16 | public static Boolean inGroup(Collection groups, Player player) { 17 | if (!SUPPORT_PERMISSION) 18 | return null; 19 | try { 20 | Permission permission = Bukkit.getServicesManager().getRegistration(Permission.class).getProvider(); 21 | return groups.stream().anyMatch(group -> permission.playerInGroup(player, group)); 22 | } catch (Throwable t) { 23 | SUPPORT_PERMISSION = false; 24 | return null; 25 | } 26 | } 27 | 28 | private static boolean SUPPORT_PERMISSION = true; 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCSeenByPlayerEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCSeenByPlayerEvent extends NPCEvent implements Cancellable { 10 | private boolean cancel; 11 | private final Player player; 12 | 13 | public NPCSeenByPlayerEvent(NPC npc, Player player) { 14 | super(npc); 15 | this.player = player; 16 | } 17 | 18 | @Override 19 | public HandlerList getHandlers() { 20 | return handlers; 21 | } 22 | 23 | public Player getPlayer() { 24 | return player; 25 | } 26 | 27 | @Override 28 | public boolean isCancelled() { 29 | return cancel; 30 | } 31 | 32 | @Override 33 | public void setCancelled(boolean cancel) { 34 | this.cancel = cancel; 35 | } 36 | 37 | public static HandlerList getHandlerList() { 38 | return handlers; 39 | } 40 | 41 | private static final HandlerList handlers = new HandlerList(); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDespawnEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | 8 | /** 9 | * Called when an NPC despawns. 10 | */ 11 | public class NPCDespawnEvent extends NPCEvent implements Cancellable { 12 | private boolean cancelled; 13 | private final DespawnReason reason; 14 | 15 | public NPCDespawnEvent(NPC npc, DespawnReason reason) { 16 | super(npc); 17 | this.reason = reason; 18 | } 19 | 20 | @Override 21 | public HandlerList getHandlers() { 22 | return handlers; 23 | } 24 | 25 | public DespawnReason getReason() { 26 | return reason; 27 | } 28 | 29 | @Override 30 | public boolean isCancelled() { 31 | return cancelled; 32 | } 33 | 34 | @Override 35 | public void setCancelled(boolean cancel) { 36 | cancelled = cancel; 37 | } 38 | 39 | public static HandlerList getHandlerList() { 40 | return handlers; 41 | } 42 | 43 | private static final HandlerList handlers = new HandlerList(); 44 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCTraitCommandAttachEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | import net.citizensnpcs.api.trait.Trait; 8 | 9 | public class NPCTraitCommandAttachEvent extends NPCEvent { 10 | private final CommandSender sender; 11 | private final Class traitClass; 12 | 13 | public NPCTraitCommandAttachEvent(NPC npc, Class traitClass, CommandSender sender) { 14 | super(npc); 15 | this.traitClass = traitClass; 16 | this.sender = sender; 17 | } 18 | 19 | public CommandSender getCommandSender() { 20 | return sender; 21 | } 22 | 23 | @Override 24 | public HandlerList getHandlers() { 25 | return handlers; 26 | } 27 | 28 | public Class getTraitClass() { 29 | return traitClass; 30 | } 31 | 32 | public static HandlerList getHandlerList() { 33 | return handlers; 34 | } 35 | 36 | private static final HandlerList handlers = new HandlerList(); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCTraitCommandDetachEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.npc.NPC; 7 | import net.citizensnpcs.api.trait.Trait; 8 | 9 | public class NPCTraitCommandDetachEvent extends NPCEvent { 10 | private final CommandSender sender; 11 | private final Class traitClass; 12 | 13 | public NPCTraitCommandDetachEvent(NPC npc, Class traitClass, CommandSender sender) { 14 | super(npc); 15 | this.traitClass = traitClass; 16 | this.sender = sender; 17 | } 18 | 19 | public CommandSender getCommandSender() { 20 | return sender; 21 | } 22 | 23 | @Override 24 | public HandlerList getHandlers() { 25 | return handlers; 26 | } 27 | 28 | public Class getTraitClass() { 29 | return traitClass; 30 | } 31 | 32 | public static HandlerList getHandlerList() { 33 | return handlers; 34 | } 35 | 36 | private static final HandlerList handlers = new HandlerList(); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/AlignmentBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.util.Vector; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Implements alignment flocking with a particular weight i.e. steering a flock of NPCs in line with each other. 11 | * 12 | * @see https://en.wikipedia.org/wiki/Flocking_(behavior) 14 | */ 15 | public class AlignmentBehavior implements FlockBehavior { 16 | private final double weight; 17 | 18 | public AlignmentBehavior(double weight) { 19 | this.weight = weight; 20 | } 21 | 22 | @Override 23 | public Vector getVector(NPC npc, Collection nearby) { 24 | Vector velocities = new Vector(0, 0, 0); 25 | for (NPC neighbor : nearby) { 26 | velocities = velocities.add(neighbor.getEntity().getVelocity()); 27 | } 28 | Vector desired = velocities.multiply((double) 1 / nearby.size()); 29 | return desired.subtract(npc.getEntity().getVelocity()).multiply(weight); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCombustByEntityEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityCombustByEntityEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCCombustByEntityEvent extends NPCCombustEvent { 10 | private final EntityCombustByEntityEvent event; 11 | 12 | public NPCCombustByEntityEvent(EntityCombustByEntityEvent event, NPC npc) { 13 | super(event, npc); 14 | this.event = event; 15 | } 16 | 17 | /** 18 | * The combuster can be a WeatherStorm a Blaze, or an Entity holding a FIRE_ASPECT enchanted item. 19 | * 20 | * @return the Entity that set the combustee alight. 21 | */ 22 | public Entity getCombuster() { 23 | return event.getCombuster(); 24 | } 25 | 26 | @Override 27 | public HandlerList getHandlers() { 28 | return handlers; 29 | } 30 | 31 | public static HandlerList getHandlerList() { 32 | return handlers; 33 | } 34 | 35 | private static final HandlerList handlers = new HandlerList(); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCombustByBlockEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityCombustByBlockEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCCombustByBlockEvent extends NPCCombustEvent { 10 | private final EntityCombustByBlockEvent event; 11 | 12 | public NPCCombustByBlockEvent(EntityCombustByBlockEvent event, NPC npc) { 13 | super(event, npc); 14 | this.event = event; 15 | } 16 | 17 | /** 18 | * The combuster can be lava or a block that is on fire. 19 | *

20 | * WARNING: block may be null. 21 | * 22 | * @return the Block that set the combustee alight. 23 | */ 24 | public Block getCombuster() { 25 | return event.getCombuster(); 26 | } 27 | 28 | @Override 29 | public HandlerList getHandlers() { 30 | return handlers; 31 | } 32 | 33 | public static HandlerList getHandlerList() { 34 | return handlers; 35 | } 36 | 37 | private static final HandlerList handlers = new HandlerList(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/TimeoutDecorator.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Decorator that forces FAILURE if child doesn't complete within a timeout. 5 | */ 6 | public class TimeoutDecorator implements Behavior { 7 | private final Behavior child; 8 | private final int maxTicks; 9 | private int ticksElapsed; 10 | 11 | public TimeoutDecorator(Behavior child, int maxTicks) { 12 | this.child = child; 13 | this.maxTicks = maxTicks; 14 | } 15 | 16 | @Override 17 | public void reset() { 18 | child.reset(); 19 | ticksElapsed = 0; 20 | } 21 | 22 | @Override 23 | public BehaviorStatus run() { 24 | if (ticksElapsed >= maxTicks) { 25 | child.reset(); 26 | return BehaviorStatus.FAILURE; 27 | } 28 | 29 | ticksElapsed++; 30 | BehaviorStatus status = child.run(); 31 | 32 | if (status != BehaviorStatus.RUNNING) { 33 | ticksElapsed = 0; 34 | } 35 | 36 | return status; 37 | } 38 | 39 | @Override 40 | public boolean shouldExecute() { 41 | return child.shouldExecute(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/TimerDecorator.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Wraps a {@link Behavior} and enforces a tick limit, after which it will return {@link BehaviorStatus#FAILURE} and 5 | * reset the child {@link Behavior}. 6 | */ 7 | public class TimerDecorator extends BehaviorGoalAdapter { 8 | private final int limit; 9 | private int ticks; 10 | private final Behavior wrapping; 11 | 12 | private TimerDecorator(Behavior wrapping, int tickLimit) { 13 | this.limit = tickLimit; 14 | this.wrapping = wrapping; 15 | } 16 | 17 | @Override 18 | public void reset() { 19 | ticks = 0; 20 | wrapping.reset(); 21 | } 22 | 23 | @Override 24 | public BehaviorStatus run() { 25 | if (++ticks >= limit) 26 | return BehaviorStatus.FAILURE; 27 | return wrapping.run(); 28 | } 29 | 30 | @Override 31 | public boolean shouldExecute() { 32 | return wrapping.shouldExecute(); 33 | } 34 | 35 | public static TimerDecorator tickLimiter(Behavior wrapping, int tickLimit) { 36 | return new TimerDecorator(wrapping, tickLimit); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCombustEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityCombustEvent; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCCombustEvent extends NPCEvent implements Cancellable { 10 | private boolean cancelled; 11 | private final EntityCombustEvent event; 12 | 13 | public NPCCombustEvent(EntityCombustEvent event, NPC npc) { 14 | super(npc); 15 | this.event = event; 16 | } 17 | 18 | public EntityCombustEvent getHandle() { 19 | return event; 20 | } 21 | 22 | @Override 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | 27 | @Override 28 | public boolean isCancelled() { 29 | return cancelled; 30 | } 31 | 32 | @Override 33 | public void setCancelled(boolean cancelled) { 34 | this.cancelled = cancelled; 35 | } 36 | 37 | public static HandlerList getHandlerList() { 38 | return handlers; 39 | } 40 | 41 | private static final HandlerList handlers = new HandlerList(); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDeathEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import java.util.List; 4 | 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.entity.EntityDeathEvent; 7 | import org.bukkit.inventory.ItemStack; 8 | 9 | import net.citizensnpcs.api.npc.NPC; 10 | 11 | public class NPCDeathEvent extends NPCEvent { 12 | private final EntityDeathEvent event; 13 | 14 | public NPCDeathEvent(NPC npc, EntityDeathEvent event) { 15 | super(npc); 16 | this.event = event; 17 | } 18 | 19 | public int getDroppedExp() { 20 | return event.getDroppedExp(); 21 | } 22 | 23 | public List getDrops() { 24 | return event.getDrops(); 25 | } 26 | 27 | public EntityDeathEvent getEvent() { 28 | return event; 29 | } 30 | 31 | @Override 32 | public HandlerList getHandlers() { 33 | return handlers; 34 | } 35 | 36 | public void setDroppedExp(int exp) { 37 | event.setDroppedExp(exp); 38 | } 39 | 40 | public static HandlerList getHandlerList() { 41 | return handlers; 42 | } 43 | 44 | private static final HandlerList handlers = new HandlerList(); 45 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/templates/CommandListExecutor.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc.templates; 2 | 3 | import java.util.List; 4 | import java.util.function.Consumer; 5 | 6 | import org.bukkit.Bukkit; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | import net.citizensnpcs.api.util.Placeholders; 10 | 11 | public class CommandListExecutor implements Consumer { 12 | private final List commands; 13 | 14 | public CommandListExecutor(List commands) { 15 | this.commands = commands; 16 | } 17 | 18 | @Override 19 | public void accept(NPC npc) { 20 | for (String command : commands) { 21 | String cmd = command; 22 | if (command.startsWith("say")) { 23 | cmd = "npc speak " + command.replaceFirst("say", "").trim() + " --target

"; 24 | } 25 | if ((cmd.startsWith("npc ") || cmd.startsWith("waypoints ") || cmd.startsWith("wp ")) 26 | && !cmd.contains("--id ")) { 27 | cmd += " --id "; 28 | } 29 | Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), Placeholders.replace(cmd, null, npc)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/CoalescedBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * A behavior that executes multiple behaviors in a single tick. 7 | */ 8 | public class CoalescedBehavior implements Behavior { 9 | private final List behaviors; 10 | 11 | public CoalescedBehavior(List behaviors) { 12 | this.behaviors = behaviors; 13 | } 14 | 15 | @Override 16 | public void reset() { 17 | for (Behavior behavior : behaviors) { 18 | behavior.reset(); 19 | } 20 | } 21 | 22 | @Override 23 | public BehaviorStatus run() { 24 | for (Behavior behavior : behaviors) { 25 | BehaviorStatus status = behavior.run(); 26 | if (status == BehaviorStatus.FAILURE || status == BehaviorStatus.RESET_AND_REMOVE) 27 | return status; 28 | } 29 | return BehaviorStatus.SUCCESS; 30 | } 31 | 32 | @Override 33 | public boolean shouldExecute() { 34 | for (Behavior behavior : behaviors) { 35 | if (behavior.shouldExecute()) 36 | return true; 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCOpenDoorEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCOpenDoorEvent extends NPCEvent implements Cancellable { 10 | private final Block block; 11 | private boolean cancelled; 12 | 13 | public NPCOpenDoorEvent(NPC npc, Block block) { 14 | super(npc); 15 | this.block = block; 16 | } 17 | 18 | /** 19 | * Returns the {@link Block} that was opened. 20 | * 21 | * @return The block 22 | */ 23 | public Block getDoor() { 24 | return block; 25 | } 26 | 27 | @Override 28 | public HandlerList getHandlers() { 29 | return handlers; 30 | } 31 | 32 | @Override 33 | public boolean isCancelled() { 34 | return cancelled; 35 | } 36 | 37 | @Override 38 | public void setCancelled(boolean arg0) { 39 | cancelled = arg0; 40 | } 41 | 42 | public static HandlerList getHandlerList() { 43 | return handlers; 44 | } 45 | 46 | private static final HandlerList handlers = new HandlerList(); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCOpenGateEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.block.Block; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class NPCOpenGateEvent extends NPCEvent implements Cancellable { 10 | private final Block block; 11 | private boolean cancelled; 12 | 13 | public NPCOpenGateEvent(NPC npc, Block block) { 14 | super(npc); 15 | this.block = block; 16 | } 17 | 18 | /** 19 | * Returns the {@link Block} that was opened. 20 | * 21 | * @return The block 22 | */ 23 | public Block getGate() { 24 | return block; 25 | } 26 | 27 | @Override 28 | public HandlerList getHandlers() { 29 | return handlers; 30 | } 31 | 32 | @Override 33 | public boolean isCancelled() { 34 | return cancelled; 35 | } 36 | 37 | @Override 38 | public void setCancelled(boolean arg0) { 39 | cancelled = arg0; 40 | } 41 | 42 | public static HandlerList getHandlerList() { 43 | return handlers; 44 | } 45 | 46 | private static final HandlerList handlers = new HandlerList(); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/PercentageSlotHandler.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.util.function.Consumer; 4 | import java.util.function.Function; 5 | 6 | public class PercentageSlotHandler implements Consumer { 7 | private int percentage; 8 | private final Function transformer; 9 | 10 | public PercentageSlotHandler(Function transformer) { 11 | this(transformer, 100); 12 | } 13 | 14 | public PercentageSlotHandler(Function transformer, int initialPercentage) { 15 | this.transformer = transformer; 16 | this.percentage = initialPercentage; 17 | } 18 | 19 | @Override 20 | public void accept(CitizensInventoryClickEvent event) { 21 | int dx = event.isShiftClick() ? 1 : 10; 22 | if (event.isRightClick()) { 23 | dx *= -1; 24 | } 25 | percentage += dx; 26 | if (percentage < 0) { 27 | percentage = 0; 28 | } else if (percentage > 100) { 29 | percentage = 100; 30 | } 31 | event.setCurrentItemDescription(transformer.apply(percentage)); 32 | event.setCancelled(true); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuTransition.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Repeatable; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import org.bukkit.event.inventory.ClickType; 10 | 11 | /** 12 | * Defines a menu transition to a new sub-menu. Can be linked to a {@link InventoryMenuTransition} or simply at the 13 | * class level. 14 | */ 15 | @Retention(RetentionPolicy.RUNTIME) 16 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 17 | @Repeatable(MenuTransitions.class) 18 | public @interface MenuTransition { 19 | /** 20 | * Whitelist the allowed clicktypes for transition (empty = all allowed). 21 | */ 22 | ClickType[] filter() default {}; 23 | 24 | /** 25 | * For use with patterns. 26 | */ 27 | char pat() default '0'; 28 | 29 | /** 30 | * The position of the slot within the inventory. 31 | */ 32 | int[] pos() default { 0, 0 }; 33 | 34 | /** 35 | * The next sub-menu class to transition to. 36 | */ 37 | Class value(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCTeleportEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Called when an NPC teleports. 11 | */ 12 | public class NPCTeleportEvent extends NPCEvent implements Cancellable { 13 | private boolean cancelled; 14 | private final Location to; 15 | 16 | public NPCTeleportEvent(NPC npc, Location to) { 17 | super(npc); 18 | this.to = to; 19 | } 20 | 21 | public Location getFrom() { 22 | return npc.getStoredLocation(); 23 | } 24 | 25 | @Override 26 | public HandlerList getHandlers() { 27 | return handlers; 28 | } 29 | 30 | public Location getTo() { 31 | return to; 32 | } 33 | 34 | @Override 35 | public boolean isCancelled() { 36 | return cancelled; 37 | } 38 | 39 | @Override 40 | public void setCancelled(boolean cancel) { 41 | cancelled = cancel; 42 | } 43 | 44 | public static HandlerList getHandlerList() { 45 | return handlers; 46 | } 47 | 48 | private static final HandlerList handlers = new HandlerList(); 49 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/Callback.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.function.Consumer; 4 | 5 | /** 6 | * Wraps an {@link Behavior} and runs callbacks when the underlying Behavior is finished. 7 | */ 8 | public class Callback extends BehaviorGoalAdapter { 9 | private final Consumer cb; 10 | private final Behavior wrapping; 11 | 12 | private Callback(Behavior wrapping, Consumer cb) { 13 | this.wrapping = wrapping; 14 | this.cb = cb; 15 | } 16 | 17 | @Override 18 | public void reset() { 19 | wrapping.reset(); 20 | } 21 | 22 | @Override 23 | public BehaviorStatus run() { 24 | BehaviorStatus status = wrapping.run(); 25 | switch (status) { 26 | case FAILURE: 27 | case SUCCESS: 28 | case RESET_AND_REMOVE: 29 | cb.accept(status); 30 | default: 31 | break; 32 | } 33 | return status; 34 | } 35 | 36 | @Override 37 | public boolean shouldExecute() { 38 | return wrapping.shouldExecute(); 39 | } 40 | 41 | public static Callback callback(Behavior wrapping, Consumer cb) { 42 | return new Callback(wrapping, cb); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCCommandDispatchEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Called just before a command list is dispatched. 11 | */ 12 | 13 | public class NPCCommandDispatchEvent extends NPCEvent implements Cancellable { 14 | private boolean cancelled; 15 | private final Player player; 16 | 17 | public NPCCommandDispatchEvent(NPC npc, Player player) { 18 | super(npc); 19 | this.player = player; 20 | } 21 | 22 | @Override 23 | public HandlerList getHandlers() { 24 | return handlers; 25 | } 26 | 27 | /** 28 | * @return the Player who will be dispatched on 29 | */ 30 | public Player getPlayer() { 31 | return player; 32 | } 33 | 34 | @Override 35 | public boolean isCancelled() { 36 | return cancelled; 37 | } 38 | 39 | @Override 40 | public void setCancelled(boolean cancel) { 41 | this.cancelled = cancel; 42 | } 43 | 44 | public static HandlerList getHandlerList() { 45 | return handlers; 46 | } 47 | 48 | private static final HandlerList handlers = new HandlerList(); 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/trait/Spawned.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait.trait; 2 | 3 | import net.citizensnpcs.api.persistence.Persist; 4 | import net.citizensnpcs.api.trait.Trait; 5 | import net.citizensnpcs.api.trait.TraitName; 6 | 7 | /** 8 | * Represents the spawn state of an NPC. This only determines whether an NPC should spawn onEnable. For checking if an 9 | * NPC's entity is spawned, use NPC.isSpawned(). 10 | */ 11 | @TraitName("spawned") 12 | public class Spawned extends Trait { 13 | @Persist("") 14 | private boolean shouldSpawn = true; 15 | 16 | public Spawned() { 17 | super("spawned"); 18 | } 19 | 20 | /** 21 | * Sets whether an NPC should spawn during server starts or reloads. 22 | * 23 | * @param shouldSpawn 24 | * Whether an NPC should spawn 25 | */ 26 | public void setSpawned(boolean shouldSpawn) { 27 | this.shouldSpawn = shouldSpawn; 28 | } 29 | 30 | /** 31 | * Gets whether an NPC should spawn during server starts or reloads. 32 | * 33 | * @return Whether an NPC should spawn 34 | */ 35 | public boolean shouldSpawn() { 36 | return shouldSpawn; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "Spawned{" + shouldSpawn + "}"; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/BlockExaminer.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import java.util.List; 4 | 5 | public interface BlockExaminer { 6 | /** 7 | * Determines if the entity can stand at this position (checks block below for support). First STANDABLE result wins 8 | * during evaluation. 9 | * 10 | * @return STANDABLE if position has valid support, NOT_STANDABLE if not, IGNORE to defer 11 | */ 12 | default StandableState canStandAt(BlockSource source, PathPoint point) { 13 | return StandableState.IGNORE; 14 | } 15 | 16 | float getCost(BlockSource source, PathPoint point); 17 | 18 | /** 19 | * Determines if the entity can pass through the block at this position. First PASSABLE result wins during 20 | * evaluation. 21 | */ 22 | PassableState isPassable(BlockSource source, PathPoint point); 23 | 24 | public static interface NeighbourGeneratorBlockExaminer extends BlockExaminer { 25 | public List getNeighbours(BlockSource source, PathPoint point); 26 | } 27 | 28 | public enum PassableState { 29 | IGNORE, 30 | IMPASSABLE, 31 | PASSABLE; 32 | } 33 | 34 | public enum StandableState { 35 | IGNORE, 36 | NOT_STANDABLE, 37 | STANDABLE; 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/InventoryMenuPattern.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The concrete instance of a {@link MenuPattern}. Defines a (possibly multiline) pattern with bound slots/transitions 7 | * depending on the pattern. 8 | */ 9 | public class InventoryMenuPattern { 10 | private final MenuPattern info; 11 | private final List slots; 12 | private final List transitions; 13 | 14 | public InventoryMenuPattern(MenuPattern info, List slots, 15 | List transitions) { 16 | this.info = info; 17 | this.slots = slots; 18 | this.transitions = transitions; 19 | } 20 | 21 | /** 22 | * @return The pattern string. 23 | */ 24 | public String getPattern() { 25 | return info.value(); 26 | } 27 | 28 | /** 29 | * @return The set of {@link InventoryMenuSlot}s that this pattern refers to. 30 | */ 31 | public List getSlots() { 32 | return slots; 33 | } 34 | 35 | /** 36 | * 37 | * @return The set of {@link InventoryMenuTransition}s that this pattern refers to. 38 | */ 39 | public List getTransitions() { 40 | return transitions; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCVehicleDamageEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.vehicle.VehicleDamageEvent; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | public class NPCVehicleDamageEvent extends NPCEvent implements Cancellable { 11 | private final Entity damager; 12 | private final VehicleDamageEvent event; 13 | 14 | public NPCVehicleDamageEvent(NPC npc, VehicleDamageEvent event) { 15 | super(npc); 16 | this.event = event; 17 | damager = event.getAttacker(); 18 | } 19 | 20 | public Entity getDamager() { 21 | return damager; 22 | } 23 | 24 | public VehicleDamageEvent getEvent() { 25 | return event; 26 | } 27 | 28 | @Override 29 | public HandlerList getHandlers() { 30 | return handlers; 31 | } 32 | 33 | @Override 34 | public boolean isCancelled() { 35 | return event.isCancelled(); 36 | } 37 | 38 | @Override 39 | public void setCancelled(boolean cancelled) { 40 | event.setCancelled(cancelled); 41 | } 42 | 43 | public static HandlerList getHandlerList() { 44 | return handlers; 45 | } 46 | 47 | private static final HandlerList handlers = new HandlerList(); 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/RetryDecorator.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | /** 4 | * Decorates a {@link Behavior} and retries failures a certain number of times. 5 | */ 6 | public class RetryDecorator extends BehaviorGoalAdapter { 7 | private final int limit; 8 | private int retries; 9 | private final Behavior wrapping; 10 | 11 | private RetryDecorator(Behavior wrapping, int limit) { 12 | this.limit = limit; 13 | this.wrapping = wrapping; 14 | } 15 | 16 | @Override 17 | public void reset() { 18 | retries = 0; 19 | wrapping.reset(); 20 | } 21 | 22 | @Override 23 | public BehaviorStatus run() { 24 | BehaviorStatus status = wrapping.run(); 25 | if (status == BehaviorStatus.FAILURE) { 26 | if (limit < 0 || ++retries < limit) { 27 | reset(); 28 | return BehaviorStatus.RUNNING; 29 | } 30 | } 31 | return status; 32 | } 33 | 34 | @Override 35 | public boolean shouldExecute() { 36 | return wrapping.shouldExecute(); 37 | } 38 | 39 | public static RetryDecorator retry(Behavior wrapping, int n) { 40 | return new RetryDecorator(wrapping, n); 41 | } 42 | 43 | public static RetryDecorator unlimited(Behavior wrapping) { 44 | return retry(wrapping, -1); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/CohesionBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.Location; 6 | import org.bukkit.util.Vector; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | /** 11 | * Implements cohesion flocking with a particular weight i.e. steering a flock of NPCs towards each other. 12 | * 13 | * @see https://en.wikipedia.org/wiki/Flocking_(behavior) 15 | */ 16 | public class CohesionBehavior implements FlockBehavior { 17 | private final double weight; 18 | 19 | public CohesionBehavior(double weight) { 20 | this.weight = weight; 21 | } 22 | 23 | @Override 24 | public Vector getVector(NPC npc, Collection nearby) { 25 | Vector positions = new Vector(0, 0, 0); 26 | Location cacheLoc = new Location(null, 0, 0, 0); 27 | for (NPC neighbor : nearby) { 28 | positions = positions.add(neighbor.getEntity().getLocation(cacheLoc).toVector()); 29 | } 30 | Vector center = positions.multiply(1.0 / nearby.size()); 31 | Vector temp = npc.getEntity().getLocation(cacheLoc).toVector().subtract(center); 32 | if (temp.length() == 0) 33 | return new Vector(0, 0, 0); 34 | return temp.normalize().multiply(weight); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/Loop.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * A decorator {@link Behavior} that continues to execute its child behavior as long as a condition returns 7 | * true and the behavior returns {@link BehaviorStatus#SUCCESS}. 8 | */ 9 | public class Loop extends BehaviorGoalAdapter { 10 | private final Supplier condition; 11 | private final Behavior wrapping; 12 | 13 | public Loop(Behavior wrapping, Supplier condition) { 14 | this.wrapping = wrapping; 15 | this.condition = condition; 16 | } 17 | 18 | @Override 19 | public void reset() { 20 | wrapping.reset(); 21 | } 22 | 23 | @Override 24 | public BehaviorStatus run() { 25 | BehaviorStatus status = wrapping.run(); 26 | if (status == BehaviorStatus.SUCCESS) { 27 | wrapping.reset(); 28 | if (condition.get() && wrapping.shouldExecute()) 29 | return BehaviorStatus.RUNNING; 30 | } 31 | return status; 32 | } 33 | 34 | @Override 35 | public boolean shouldExecute() { 36 | return wrapping.shouldExecute(); 37 | } 38 | 39 | public static Loop createWithCondition(Behavior wrapping, Supplier condition) { 40 | return new Loop(wrapping, condition); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/Talkable.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech; 2 | 3 | import org.bukkit.entity.Entity; 4 | 5 | /** 6 | * Talkable provides an interface for talking to Players, Entities and NPCs. 7 | * 8 | */ 9 | public interface Talkable extends Comparable { 10 | /** 11 | * Gets the LivingEntity associated with this Talkable 12 | * 13 | * @return a LivingEntity 14 | */ 15 | public Entity getEntity(); 16 | 17 | /** 18 | * Gets the name of the Talkable LivingEntity 19 | * 20 | * @return name 21 | */ 22 | public String getName(); 23 | 24 | /** 25 | * Called when talking near this Talkable Entity to provide a universal method to getting an event/output. 26 | * 27 | * @param context 28 | * the Speech context 29 | * @param message 30 | * The message to send 31 | * 32 | */ 33 | public void talkNear(SpeechContext context, String message); 34 | 35 | /** 36 | * Called when talking to this Talkable Entity to provide a universal method to getting an event/output. 37 | * 38 | * @param context 39 | * the Speech context 40 | * @param message 41 | * The message to send 42 | */ 43 | public void talkTo(SpeechContext context, String message); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/PotionEffectPersister.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.potion.PotionEffect; 5 | import org.bukkit.potion.PotionEffectType; 6 | 7 | import net.citizensnpcs.api.util.DataKey; 8 | import net.citizensnpcs.api.util.SpigotUtil; 9 | 10 | public class PotionEffectPersister implements Persister { 11 | @Override 12 | public PotionEffect create(DataKey root) { 13 | return new PotionEffect( 14 | Bukkit.getRegistry(PotionEffectType.class).get(SpigotUtil.getKey(root.getString("type"))), 15 | root.getInt("duration"), root.getInt("amplifier"), root.getBoolean("ambient"), 16 | root.getBoolean("particles"), root.getBoolean("icon")); 17 | } 18 | 19 | @Override 20 | public void save(PotionEffect effect, DataKey root) { 21 | String effectTypeKey = effect.getType().getKey() != null 22 | ? effect.getType().getKey().toString() 23 | : null; 24 | root.setString("type", effectTypeKey); 25 | root.setInt("amplifier", effect.getAmplifier()); 26 | root.setInt("duration", effect.getDuration()); 27 | root.setBoolean("particles", effect.hasParticles()); 28 | root.setBoolean("ambient", effect.isAmbient()); 29 | root.setBoolean("icon", effect.hasIcon()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCClickEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Represents an event where an NPC was clicked by a player. 11 | */ 12 | public abstract class NPCClickEvent extends NPCEvent implements Cancellable { 13 | private boolean cancelled = false; 14 | private final Player clicker; 15 | 16 | protected NPCClickEvent(NPC npc, Player clicker) { 17 | super(npc); 18 | this.clicker = clicker; 19 | } 20 | 21 | /** 22 | * Gets the player that clicked the NPC. 23 | * 24 | * @return Player that clicked the NPC 25 | */ 26 | public Player getClicker() { 27 | return clicker; 28 | } 29 | 30 | @Override 31 | public HandlerList getHandlers() { 32 | return handlers; 33 | } 34 | 35 | @Override 36 | public boolean isCancelled() { 37 | return cancelled; 38 | } 39 | 40 | @Override 41 | public void setCancelled(boolean cancelled) { 42 | this.cancelled = cancelled; 43 | } 44 | 45 | public static HandlerList getHandlerList() { 46 | return handlers; 47 | } 48 | 49 | private static final HandlerList handlers = new HandlerList(); 50 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/event/NPCSpeechEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import net.citizensnpcs.api.CitizensAPI; 7 | import net.citizensnpcs.api.ai.speech.SpeechContext; 8 | import net.citizensnpcs.api.event.NPCEvent; 9 | 10 | /** 11 | * Represents an event where an NPC speaks using /npc speak. 12 | */ 13 | public class NPCSpeechEvent extends NPCEvent implements Cancellable { 14 | private boolean cancelled = false; 15 | private final SpeechContext context; 16 | 17 | public NPCSpeechEvent(SpeechContext context) { 18 | super(CitizensAPI.getNPCRegistry().getNPC(context.getTalker().getEntity())); 19 | this.context = context; 20 | } 21 | 22 | public SpeechContext getContext() { 23 | return context; 24 | } 25 | 26 | @Override 27 | public HandlerList getHandlers() { 28 | return handlers; 29 | } 30 | 31 | @Override 32 | public boolean isCancelled() { 33 | return cancelled; 34 | } 35 | 36 | @Override 37 | public void setCancelled(boolean cancelled) { 38 | this.cancelled = cancelled; 39 | } 40 | 41 | public static HandlerList getHandlerList() { 42 | return handlers; 43 | } 44 | 45 | private static final HandlerList handlers = new HandlerList(); 46 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/VectorGoal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.util.Vector; 5 | 6 | import net.citizensnpcs.api.astar.AStarGoal; 7 | 8 | public class VectorGoal implements AStarGoal { 9 | private final Vector goal; 10 | private final float leeway; 11 | 12 | public VectorGoal(Location dest, float range) { 13 | if (!MinecraftBlockExaminer.canStandIn(dest.getBlock())) { 14 | dest = MinecraftBlockExaminer.findValidLocationAbove(dest, 2); 15 | } 16 | this.leeway = range; 17 | this.goal = dest.toVector().setX(dest.getBlockX()).setY(dest.getBlockY()).setZ(dest.getBlockZ()); 18 | } 19 | 20 | @Override 21 | public float g(VectorNode from, VectorNode to) { 22 | return from.distance(to); 23 | } 24 | 25 | public Vector getGoalVector() { 26 | return goal.clone(); 27 | } 28 | 29 | @Override 30 | public float getInitialCost(VectorNode node) { 31 | return (float) node.getVector().distance(goal); 32 | } 33 | 34 | @Override 35 | public float h(VectorNode from) { 36 | return from.heuristicDistance(goal); 37 | } 38 | 39 | @Override 40 | public boolean isFinished(VectorNode node) { 41 | double distance = node.location.distance(goal); 42 | return goal.equals(node.location) || distance <= leeway; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/AStarGoal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | public interface AStarGoal { 4 | /** 5 | * Returns the cost of moving between the two supplied {@link AStarNode}s. 6 | * 7 | * @param from 8 | * The node to start from 9 | * @param to 10 | * The end node 11 | * @return The cost 12 | */ 13 | float g(T from, T to); 14 | 15 | /** 16 | * Returns the initial cost value when starting from the supplied {@link AStarNode}. This represents an initial 17 | * estimate for reaching the goal state from the start node. 18 | * 19 | * @param node 20 | * The start node 21 | * @return The initial cost 22 | */ 23 | float getInitialCost(T node); 24 | 25 | /** 26 | * Returns the estimated heuristic cost of traversing from the supplied {@link AStarNode} to the goal. 27 | * 28 | * @param from 29 | * The start node 30 | * @return The heuristic cost 31 | */ 32 | float h(T from); 33 | 34 | /** 35 | * Returns whether the supplied {@link AStarNode} represents the goal state for this AStarGoal. This 36 | * will halt execution of the calling {@link AStarMachine}. 37 | * 38 | * @param node 39 | * The node to check 40 | * @return Whether the node is the goal state 41 | */ 42 | boolean isFinished(T node); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/AStarNode.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | import java.util.Collections; 4 | import java.util.List; 5 | 6 | import com.google.common.collect.Lists; 7 | 8 | public abstract class AStarNode implements Comparable { 9 | float g, h; 10 | AStarNode parent; 11 | List parents; 12 | 13 | protected AStarNode(AStarNode parent) { 14 | this.parent = parent; 15 | } 16 | 17 | public abstract Plan buildPlan(); 18 | 19 | @Override 20 | public int compareTo(AStarNode other) { 21 | return Float.compare(g + h, other.g + other.h); 22 | } 23 | 24 | @Override 25 | public abstract boolean equals(Object other); 26 | 27 | public abstract Iterable getNeighbours(); 28 | 29 | protected AStarNode getParent() { 30 | return parent; 31 | } 32 | 33 | protected float getPathCost() { 34 | return g + h; 35 | } 36 | 37 | @Override 38 | public abstract int hashCode(); 39 | 40 | @SuppressWarnings("unchecked") 41 | protected Iterable orderedPath() { 42 | if (parents != null) 43 | return (Iterable) parents; 44 | parents = Lists.newArrayList(); 45 | AStarNode start = this; 46 | while (start != null) { 47 | parents.add(start); 48 | start = start.parent; 49 | } 50 | Collections.reverse(parents); 51 | return (Iterable) parents; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCPushEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.util.Vector; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | public class NPCPushEvent extends NPCEvent implements Cancellable { 11 | private boolean cancelled; 12 | private final Vector collisionVector; 13 | private final Entity pushedBy; 14 | 15 | public NPCPushEvent(NPC npc, Vector vector, Entity pushedBy) { 16 | super(npc); 17 | this.collisionVector = vector; 18 | this.pushedBy = pushedBy; 19 | } 20 | 21 | /** 22 | * Return the collision {@link Vector} being applied to the NPC. 23 | * 24 | * @return The collision vector 25 | */ 26 | public Vector getCollisionVector() { 27 | return collisionVector; 28 | } 29 | 30 | @Override 31 | public HandlerList getHandlers() { 32 | return handlers; 33 | } 34 | 35 | public Entity getPushedBy() { 36 | return pushedBy; 37 | } 38 | 39 | @Override 40 | public boolean isCancelled() { 41 | return cancelled; 42 | } 43 | 44 | @Override 45 | public void setCancelled(boolean cancel) { 46 | cancelled = cancel; 47 | } 48 | 49 | public static HandlerList getHandlerList() { 50 | return handlers; 51 | } 52 | 53 | private static final HandlerList handlers = new HandlerList(); 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCKnockbackEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.util.Vector; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | public class NPCKnockbackEvent extends NPCEvent implements Cancellable { 11 | private boolean cancelled; 12 | private final Entity entity; 13 | private final double strength; 14 | private final Vector vector; 15 | 16 | public NPCKnockbackEvent(NPC npc, double strength, Vector vector, Entity entity) { 17 | super(npc); 18 | this.entity = entity; 19 | this.strength = strength; 20 | this.vector = vector; 21 | } 22 | 23 | @Override 24 | public HandlerList getHandlers() { 25 | return handlers; 26 | } 27 | 28 | public Vector getKnockbackVector() { 29 | return vector; 30 | } 31 | 32 | public Entity getKnockingBackEntity() { 33 | return entity; 34 | } 35 | 36 | public double getStrength() { 37 | return strength; 38 | } 39 | 40 | @Override 41 | public boolean isCancelled() { 42 | return cancelled; 43 | } 44 | 45 | @Override 46 | public void setCancelled(boolean cancel) { 47 | this.cancelled = cancel; 48 | } 49 | 50 | public static HandlerList getHandlerList() { 51 | return handlers; 52 | } 53 | 54 | private static final HandlerList handlers = new HandlerList(); 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/ForwardingBehaviorGoalAdapter.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * Forwards all calls to a secondary {@link Behavior}. 7 | */ 8 | public class ForwardingBehaviorGoalAdapter extends BehaviorGoalAdapter { 9 | private final Behavior behavior; 10 | 11 | public ForwardingBehaviorGoalAdapter(Behavior behavior) { 12 | this.behavior = behavior; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object obj) { 17 | if (this == obj) 18 | return true; 19 | if (obj == null || getClass() != obj.getClass()) 20 | return false; 21 | ForwardingBehaviorGoalAdapter other = (ForwardingBehaviorGoalAdapter) obj; 22 | if (!Objects.equals(behavior, other.behavior)) 23 | return false; 24 | return true; 25 | } 26 | 27 | public Behavior getWrapped() { 28 | return behavior; 29 | } 30 | 31 | @Override 32 | public int hashCode() { 33 | return 31 + (behavior == null ? 0 : behavior.hashCode()); 34 | } 35 | 36 | @Override 37 | public void reset() { 38 | behavior.reset(); 39 | } 40 | 41 | @Override 42 | public BehaviorStatus run() { 43 | return behavior.run(); 44 | } 45 | 46 | @Override 47 | public boolean shouldExecute() { 48 | return behavior.shouldExecute(); 49 | } 50 | 51 | @Override 52 | public String toString() { 53 | return "ForwardingBehaviorGoalAdapter [behavior=" + behavior + "]"; 54 | } 55 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CitizensAPI README 2 | ================== 3 | 4 | CitizensAPI is an API framework for developers to use. It provides methods for creating and maintaining NPCs, as well as attaching custom data to NPCs. 5 | 6 | Compatible With: 7 | - All versions of Minecraft with Spigot/Bukkit (http://wiki.citizensnpcs.co/Versions for more) 8 | 9 | Maven 10 | ===== 11 | 12 | IF YOU ARE USING THE API (which you probably should **not** be if you're just integrating the Citizens plugin!), Include CitizensAPI in your pom.xml like this: (If you are integrating your own plugin with the Citizens plugin, see https://wiki.citizensnpcs.co/API for information on appropriate maven linkage.) 13 | ```xml 14 | 15 | citizens-repo 16 | https://maven.citizensnpcs.co/repo 17 | 18 | 19 | net.citizensnpcs 20 | citizensapi 21 | CITIZENS_VERSION 22 | jar 23 | compile 24 | 25 | ``` 26 | 27 | The correct CITIZENS_VERSION to use can depend on your minecraft version. A list can be found here https://maven.citizensnpcs.co/#/repo/net/citizensnpcs/ - or you can use the version listed in the Citizens2 JAR you downloaded (e.g. `2.0.30-SNAPSHOT`). 28 | 29 | Javadoc 30 | ======= 31 | 32 | http://jd.citizensnpcs.co 33 | 34 | Extra information 35 | ================= 36 | 37 | Spigot page: https://www.spigotmc.org/resources/citizens.13811/ 38 | 39 | For questions/help join our discord at: https://discord.gg/Q6pZGSR 40 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/GroupNPCFlock.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | /** 11 | * Defines a static flock of NPCs with an optional radius. If the radius is positive then NPCs will only be considered 12 | * part of the flock if they are within the base NPC's radius currently. 13 | */ 14 | public class GroupNPCFlock implements NPCFlock { 15 | private final List npcs; 16 | private final double radius; 17 | 18 | public GroupNPCFlock(Iterable npcs, double radius) { 19 | this.npcs = new ArrayList<>(); 20 | this.radius = radius; 21 | } 22 | 23 | @Override 24 | public Collection getNearby(final NPC npc) { 25 | if (radius < 0) 26 | return npcs; 27 | return npcs.stream() 28 | .filter(input -> npc.getStoredLocation().getWorld() == input.getStoredLocation().getWorld() 29 | && input.getStoredLocation().distance(npc.getStoredLocation()) < radius) 30 | .collect(Collectors. toList()); 31 | } 32 | 33 | public List getNPCs() { 34 | return npcs; 35 | } 36 | 37 | public static GroupNPCFlock create(Iterable npcs) { 38 | return new GroupNPCFlock(npcs, -1); 39 | } 40 | 41 | public static GroupNPCFlock createWithRadius(Iterable npcs, double radius) { 42 | return new GroupNPCFlock(npcs, radius); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/ChunkSnapshotBlockSource.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import org.bukkit.ChunkSnapshot; 4 | import org.bukkit.Location; 5 | import org.bukkit.Material; 6 | import org.bukkit.World; 7 | import org.bukkit.block.data.BlockData; 8 | 9 | import net.citizensnpcs.api.util.BoundingBox; 10 | 11 | public class ChunkSnapshotBlockSource extends CachingChunkBlockSource { 12 | public ChunkSnapshotBlockSource(Location location, float radius) { 13 | super(location, radius); 14 | } 15 | 16 | public ChunkSnapshotBlockSource(World world, int x, int z, float radius) { 17 | super(world, x, z, radius); 18 | } 19 | 20 | @Override 21 | protected BlockData getBlockData(ChunkSnapshot chunk, int x, int y, int z) { 22 | return chunk.getBlockData(x & 15, y, z & 15); 23 | } 24 | 25 | @Override 26 | protected ChunkSnapshot getChunkObject(int x, int z) { 27 | return world.getChunkAt(x, z).getChunkSnapshot(false, false, false); 28 | } 29 | 30 | @Override 31 | protected BoundingBox getCollisionBox(ChunkSnapshot chunk, int x, int y, int z) { 32 | return null; // TODO 33 | } 34 | 35 | @Override 36 | protected int getLightLevel(ChunkSnapshot chunk, int x, int y, int z) { 37 | return Math.min(15, chunk.getBlockSkyLight(x, y, z) + chunk.getBlockEmittedLight(x, y, z)); 38 | } 39 | 40 | @Override 41 | protected Material getType(ChunkSnapshot chunk, int x, int y, int z) { 42 | return chunk.getBlockType(x & 15, y, z & 15); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/EntityTargetNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.entity.Entity; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.entity.EntityTargetEvent; 7 | import org.bukkit.event.entity.EntityTargetEvent.TargetReason; 8 | 9 | import net.citizensnpcs.api.npc.NPC; 10 | 11 | public class EntityTargetNPCEvent extends NPCEvent implements Cancellable { 12 | private final EntityTargetEvent event; 13 | 14 | public EntityTargetNPCEvent(EntityTargetEvent event, NPC npc) { 15 | super(npc); 16 | this.event = event; 17 | } 18 | 19 | /** 20 | * Returns the Entity involved in this event 21 | * 22 | * @return Entity who is involved in this event 23 | */ 24 | public Entity getEntity() { 25 | return event.getEntity(); 26 | } 27 | 28 | @Override 29 | public HandlerList getHandlers() { 30 | return handlers; 31 | } 32 | 33 | /** 34 | * Returns the reason for the targeting 35 | * 36 | * @return The reason 37 | */ 38 | public TargetReason getReason() { 39 | return event.getReason(); 40 | } 41 | 42 | @Override 43 | public boolean isCancelled() { 44 | return event.isCancelled(); 45 | } 46 | 47 | @Override 48 | public void setCancelled(boolean cancel) { 49 | event.setCancelled(cancel); 50 | } 51 | 52 | public static HandlerList getHandlerList() { 53 | return handlers; 54 | } 55 | 56 | private static final HandlerList handlers = new HandlerList(); 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/expr/CompiledExpression.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.expr; 2 | 3 | /** 4 | * A compiled expression that can be evaluated against a scope. 5 | */ 6 | public interface CompiledExpression { 7 | Object evaluate(ExpressionScope scope); 8 | 9 | default boolean evaluateAsBoolean(ExpressionScope scope) { 10 | Object result = evaluate(scope); 11 | if (result == null) 12 | return false; 13 | 14 | if (result instanceof Boolean) 15 | return (Boolean) result; 16 | 17 | if (result instanceof Number) 18 | return ((Number) result).doubleValue() != 0; 19 | 20 | if (result instanceof String) 21 | return !((String) result).isEmpty(); 22 | 23 | return true; 24 | } 25 | 26 | default double evaluateAsNumber(ExpressionScope scope) { 27 | Object result = evaluate(scope); 28 | if (result == null) 29 | return 0; 30 | 31 | if (result instanceof Number) 32 | return ((Number) result).doubleValue(); 33 | 34 | if (result instanceof Boolean) 35 | return ((Boolean) result) ? 1 : 0; 36 | 37 | if (result instanceof String) { 38 | try { 39 | return Double.parseDouble((String) result); 40 | } catch (NumberFormatException e) { 41 | return 0; 42 | } 43 | } 44 | return 0; 45 | } 46 | 47 | default String evaluateAsString(ExpressionScope scope) { 48 | Object result = evaluate(scope); 49 | return result == null ? "" : result.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/TraitTemplateParser.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait; 2 | 3 | import java.util.function.BiFunction; 4 | 5 | import net.citizensnpcs.api.command.CommandContext; 6 | import net.citizensnpcs.api.npc.NPC; 7 | import net.citizensnpcs.api.npc.templates.TemplateWorkspace; 8 | import net.citizensnpcs.api.persistence.PersistenceLoader; 9 | import net.citizensnpcs.api.util.DataKey; 10 | 11 | public interface TraitTemplateParser { 12 | ShortTemplateParser getShortTemplateParser(); 13 | 14 | TemplateParser getTemplateParser(); 15 | 16 | public static interface ShortTemplateParser extends BiFunction { 17 | } 18 | 19 | public static interface TemplateParser extends BiFunction { 20 | } 21 | 22 | public static class TraitParserContext { 23 | public final NPC npc; 24 | public final TemplateWorkspace workspace; 25 | 26 | public TraitParserContext(NPC npc, TemplateWorkspace workspace) { 27 | this.npc = npc; 28 | this.workspace = workspace; 29 | } 30 | } 31 | 32 | static TraitTemplateParser createDefault(Class traitClass) { 33 | return new TraitTemplateParser() { 34 | @Override 35 | public ShortTemplateParser getShortTemplateParser() { 36 | return null; 37 | } 38 | 39 | @Override 40 | public TemplateParser getTemplateParser() { 41 | return (ctx, key) -> PersistenceLoader.load(traitClass, key); 42 | } 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/IfElse.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * A simple if-then-else {@link Behavior} which will execute a different {@link Behavior} depending on an 7 | * {@link Condition} function. 8 | */ 9 | public class IfElse extends BehaviorGoalAdapter { 10 | private final Supplier condition; 11 | private Behavior executing; 12 | private final Behavior ifBehavior, elseBehavior; 13 | 14 | public IfElse(Supplier condition, Behavior ifBehavior, Behavior elseBehavior) { 15 | this.condition = condition; 16 | this.ifBehavior = ifBehavior; 17 | this.elseBehavior = elseBehavior; 18 | } 19 | 20 | @Override 21 | public void reset() { 22 | if (executing != null) { 23 | executing.reset(); 24 | executing = null; 25 | } 26 | } 27 | 28 | @Override 29 | public BehaviorStatus run() { 30 | return executing.run(); 31 | } 32 | 33 | @Override 34 | public boolean shouldExecute() { 35 | boolean cond = condition.get(); 36 | if (cond) { 37 | executing = ifBehavior; 38 | } else { 39 | executing = elseBehavior; 40 | } 41 | if (executing == null || !executing.shouldExecute()) { 42 | executing = null; 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | public static IfElse create(Supplier condition, Behavior ifBehavior, Behavior elseBehavior) { 49 | return new IfElse(condition, ifBehavior, elseBehavior); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCDamageEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | import org.bukkit.event.entity.EntityDamageEvent; 6 | import org.bukkit.event.entity.EntityDamageEvent.DamageCause; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | public class NPCDamageEvent extends NPCEvent implements Cancellable { 11 | private final EntityDamageEvent event; 12 | 13 | public NPCDamageEvent(NPC npc, EntityDamageEvent event) { 14 | super(npc); 15 | this.event = event; 16 | } 17 | 18 | public DamageCause getCause() { 19 | return event.getCause(); 20 | } 21 | 22 | public double getDamage() { 23 | return event.getDamage(); 24 | } 25 | 26 | public EntityDamageEvent getEvent() { 27 | return event; 28 | } 29 | 30 | @Override 31 | public HandlerList getHandlers() { 32 | return handlers; 33 | } 34 | 35 | @Override 36 | public boolean isCancelled() { 37 | return event.isCancelled(); 38 | } 39 | 40 | @Override 41 | public void setCancelled(boolean cancel) { 42 | event.setCancelled(cancel); 43 | } 44 | 45 | public void setDamage(double damage) { 46 | event.setDamage(damage); 47 | } 48 | 49 | public void setDamage(int damage) { 50 | event.setDamage(damage); 51 | } 52 | 53 | public static HandlerList getHandlerList() { 54 | return handlers; 55 | } 56 | 57 | private static final HandlerList handlers = new HandlerList(); 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCSpawnEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Called when an NPC spawns. 11 | */ 12 | public class NPCSpawnEvent extends NPCEvent implements Cancellable { 13 | private boolean cancelled = false; 14 | private final Location location; 15 | private final SpawnReason reason; 16 | 17 | public NPCSpawnEvent(NPC npc, Location location, SpawnReason reason) { 18 | super(npc); 19 | this.location = location; 20 | this.reason = reason; 21 | } 22 | 23 | @Override 24 | public HandlerList getHandlers() { 25 | return handlers; 26 | } 27 | 28 | /** 29 | * Gets the location where the NPC was spawned. 30 | * 31 | * @return Location where the NPC was spawned 32 | */ 33 | public Location getLocation() { 34 | return location.clone(); 35 | } 36 | 37 | /** 38 | * Gets the reason for spawning the NPC. 39 | * 40 | * @return Reason for spawning the NPC 41 | */ 42 | public SpawnReason getReason() { 43 | return reason; 44 | } 45 | 46 | @Override 47 | public boolean isCancelled() { 48 | return cancelled; 49 | } 50 | 51 | @Override 52 | public void setCancelled(boolean cancelled) { 53 | this.cancelled = cancelled; 54 | } 55 | 56 | public static HandlerList getHandlerList() { 57 | return handlers; 58 | } 59 | 60 | private static final HandlerList handlers = new HandlerList(); 61 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/PathStrategy.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.util.Vector; 5 | 6 | import net.citizensnpcs.api.ai.event.CancelReason; 7 | 8 | /** 9 | * A pathfinding strategy directed at a target. Has two states: pathfinding -> cancelled represented by 10 | * {@link #getCancelReason()}. 11 | */ 12 | public interface PathStrategy { 13 | /** 14 | * Clears the CancelReason returned by {@link #getCancelReason()} and attempts to resume pathfinding. 15 | */ 16 | void clearCancelReason(); 17 | 18 | /** 19 | * @return The reason for the pathfinding to stop, or null if it is still continuing. 20 | */ 21 | CancelReason getCancelReason(); 22 | 23 | /** 24 | * 25 | * @return Gets the current movement destination 26 | */ 27 | Location getCurrentDestination(); 28 | 29 | /** 30 | * @return A copy of the current path, if any 31 | */ 32 | Iterable getPath(); 33 | 34 | /** 35 | * @return Gets the target destination location 36 | */ 37 | Location getTargetAsLocation(); 38 | 39 | /** 40 | * @return The {@link TargetType} of this strategy 41 | */ 42 | TargetType getTargetType(); 43 | 44 | /** 45 | * Forcibly stops pathfinding. Note that this method does not necessarily set the cancel reason. 46 | */ 47 | void stop(); 48 | 49 | /** 50 | * Updates and runs the pathfinding strategy on its current NPC and destination. 51 | * 52 | * @return Whether pathfinding has completed 53 | */ 54 | boolean update(); 55 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/TeleportStuckAction.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.block.Block; 5 | import org.bukkit.block.BlockFace; 6 | import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; 7 | 8 | import net.citizensnpcs.api.astar.pathfinder.MinecraftBlockExaminer; 9 | import net.citizensnpcs.api.npc.NPC; 10 | 11 | public class TeleportStuckAction implements StuckAction { 12 | private TeleportStuckAction() { 13 | // singleton 14 | } 15 | 16 | @Override 17 | public boolean run(NPC npc, Navigator navigator) { 18 | if (!npc.isSpawned()) 19 | return false; 20 | Location base = navigator.getTargetAsLocation(); 21 | if (base == null || base.getWorld() != npc.getEntity().getWorld()) 22 | return true; 23 | Block block = base.getBlock().getRelative(BlockFace.DOWN); 24 | int iterations = 0; 25 | while (!MinecraftBlockExaminer.canStandOn(block)) { 26 | if (iterations++ >= MAX_ITERATIONS) { 27 | block = base.getBlock().getRelative(BlockFace.DOWN); 28 | break; 29 | } 30 | block = block.getRelative(BlockFace.UP); 31 | } 32 | npc.teleport(block.getRelative(BlockFace.UP).getLocation(), TeleportCause.PLUGIN); 33 | return false; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "TeleportStuckAction"; 39 | } 40 | 41 | public static final TeleportStuckAction INSTANCE = new TeleportStuckAction(); 42 | private static final int MAX_ITERATIONS = 10; 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuSlot.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Repeatable; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import org.bukkit.Material; 10 | 11 | /** 12 | * Defines a slot with a certain item. Can be linked to a {@link InventoryMenuSlot} or simply at the class level. 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD }) 16 | @Repeatable(MenuSlots.class) 17 | public @interface MenuSlot { 18 | /** 19 | * The amount of the itemstack to display. 20 | */ 21 | int amount() default 1; 22 | 23 | /** 24 | * For compatibility with old Minecraft versions - a two String array {intended material name, fallback material 25 | * name} e.g. {"SHIELD", "AIR"} 26 | */ 27 | String[] compatMaterial() default {}; 28 | 29 | /** 30 | * The lore of the inventory item, newline-delimited. 31 | */ 32 | String lore() default "EMPTY"; 33 | 34 | /** 35 | * The material to display (defaults to AIR). For extra customisation see {@link InventoryMenuSlot}. 36 | */ 37 | Material material() default Material.AIR; 38 | 39 | /** 40 | * For use with patterns. 41 | */ 42 | char pat() default '0'; 43 | 44 | /** 45 | * The position of the slot within the inventory. 46 | */ 47 | int[] slot() default { 0, 0 }; 48 | 49 | /** 50 | * The display name of the inventory item. 51 | */ 52 | String title() default "EMPTY"; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/SeparationBehavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.util.Vector; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | /** 10 | * Implements separation flocking with a particular weight i.e. steering a flock of NPCs away from each other. 11 | * 12 | * @see https://en.wikipedia.org/wiki/Flocking_(behavior) 14 | */ 15 | public class SeparationBehavior implements FlockBehavior { 16 | private double separation = 0.5; 17 | private final double weight; 18 | 19 | public SeparationBehavior(double weight) { 20 | this.weight = weight; 21 | } 22 | 23 | public SeparationBehavior(double weight, double separation) { 24 | this.separation = separation; 25 | this.weight = weight; 26 | } 27 | 28 | @Override 29 | public Vector getVector(NPC npc, Collection nearby) { 30 | Vector steering = new Vector(0, 0, 0); 31 | Vector pos = npc.getEntity().getLocation().toVector(); 32 | int count = 0; 33 | for (NPC neighbor : nearby) { 34 | Vector diff = pos.subtract(neighbor.getEntity().getLocation().toVector()).setY(0); 35 | double dist = diff.length(); 36 | if (dist > separation || dist == 0) { 37 | continue; 38 | } 39 | steering = steering.add(diff.normalize().multiply(1 / (dist * 50))); 40 | count++; 41 | } 42 | count = Math.max(1, count); 43 | steering = steering.divide(new Vector(count, count, count)); 44 | return steering.setY(0).multiply(weight); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/Injector.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | import java.lang.invoke.MethodType; 5 | import java.lang.reflect.Constructor; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import net.citizensnpcs.api.util.Messaging; 10 | 11 | public class Injector { 12 | private final Class[] argClasses; 13 | private final List args; 14 | 15 | public Injector(Object... args) { 16 | this.args = Arrays.asList(args); 17 | argClasses = new Class[args.length]; 18 | for (int i = 0; i < args.length; ++i) { 19 | argClasses[i] = args[i].getClass(); 20 | } 21 | } 22 | 23 | public Object getInstance(Class clazz) { 24 | try { 25 | return LOOKUP.findConstructor(clazz, MethodType.methodType(void.class, argClasses)) 26 | .invokeWithArguments(args); 27 | } catch (NoSuchMethodException | IllegalAccessException e) { 28 | try { 29 | Constructor ctr = clazz.getDeclaredConstructor(); 30 | ctr.setAccessible(true); 31 | return ctr.newInstance(); 32 | } catch (Exception ex) { 33 | Messaging.severe("Error initializing commands class " + clazz + ": "); 34 | ex.printStackTrace(); 35 | return null; 36 | } 37 | } catch (Throwable e) { 38 | Messaging.severe("Error initializing commands class " + clazz + ": "); 39 | e.printStackTrace(); 40 | return null; 41 | } 42 | } 43 | 44 | private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 45 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/util/EntityDim.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.util; 2 | 3 | import java.util.Objects; 4 | 5 | import org.bukkit.entity.Entity; 6 | 7 | public class EntityDim { 8 | public final float height; 9 | public final float width; 10 | 11 | public EntityDim(double width, double height) { 12 | this((float) width, (float) height); 13 | } 14 | 15 | public EntityDim(float width, float height) { 16 | this.width = width; 17 | this.height = height; 18 | } 19 | 20 | @Override 21 | public EntityDim clone() { 22 | return new EntityDim(width, height); 23 | } 24 | 25 | @Override 26 | public boolean equals(Object obj) { 27 | if (this == obj) 28 | return true; 29 | if (obj == null || getClass() != obj.getClass()) 30 | return false; 31 | EntityDim other = (EntityDim) obj; 32 | if ((Double.doubleToLongBits(height) != Double.doubleToLongBits(other.height)) 33 | || (Double.doubleToLongBits(width) != Double.doubleToLongBits(other.width))) 34 | return false; 35 | return true; 36 | } 37 | 38 | @Override 39 | public int hashCode() { 40 | return Objects.hash(height, width); 41 | } 42 | 43 | public EntityDim mul(float scale) { 44 | return new EntityDim(width * scale, height * scale); 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return "EntityDim [height=" + height + ", width=" + width + "]"; 50 | } 51 | 52 | public static EntityDim from(BoundingBox bb) { 53 | return new EntityDim(bb.maxX - bb.minX, bb.maxY - bb.minY); 54 | } 55 | 56 | public static EntityDim from(Entity entity) { 57 | return new EntityDim(entity.getWidth(), entity.getHeight()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/goals/MoveToGoal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.goals; 2 | 3 | import org.bukkit.Location; 4 | 5 | import net.citizensnpcs.api.ai.Goal; 6 | import net.citizensnpcs.api.ai.event.CancelReason; 7 | import net.citizensnpcs.api.ai.tree.Behavior; 8 | import net.citizensnpcs.api.ai.tree.BehaviorGoalAdapter; 9 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 10 | import net.citizensnpcs.api.npc.NPC; 11 | 12 | /** 13 | * A sample {@link Goal}/{@link Behavior} that simply moves an {@link NPC} to a specified {@link Location}. 14 | */ 15 | public class MoveToGoal extends BehaviorGoalAdapter { 16 | private boolean finished; 17 | private final NPC npc; 18 | private CancelReason reason; 19 | private final Location target; 20 | 21 | public MoveToGoal(NPC npc, Location target) { 22 | this.npc = npc; 23 | this.target = target; 24 | } 25 | 26 | @Override 27 | public void reset() { 28 | npc.getNavigator().cancelNavigation(); 29 | reason = null; 30 | finished = false; 31 | } 32 | 33 | @Override 34 | public BehaviorStatus run() { 35 | if (finished) 36 | return reason == null ? BehaviorStatus.SUCCESS : BehaviorStatus.FAILURE; 37 | return BehaviorStatus.RUNNING; 38 | } 39 | 40 | @Override 41 | public boolean shouldExecute() { 42 | boolean executing = !npc.getNavigator().isNavigating() && target != null; 43 | if (executing) { 44 | npc.getNavigator().setTarget(target); 45 | npc.getNavigator().getLocalParameters().addSingleUseCallback(cancelReason -> { 46 | finished = true; 47 | reason = cancelReason; 48 | }); 49 | } 50 | return executing; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/RadiusNPCFlock.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.entity.Entity; 6 | 7 | import com.google.common.collect.Lists; 8 | 9 | import net.citizensnpcs.api.CitizensAPI; 10 | import net.citizensnpcs.api.npc.NPC; 11 | 12 | /** 13 | * A dynamic flock of NPCs that checks for entity NPCs within a certain block radius. 14 | */ 15 | public class RadiusNPCFlock implements NPCFlock { 16 | private Collection cached; 17 | private int cacheTicks = 0; 18 | private final int maxCacheTicks; 19 | private final double radius; 20 | 21 | public RadiusNPCFlock(double radius) { 22 | this(radius, 30); 23 | } 24 | 25 | /** 26 | * 27 | * @param radius 28 | * the radius to look for nearby NPCs, in blocks @see 29 | * {@link Entity#getNearbyEntities(double, double, double)} 30 | * @param maxCacheTicks 31 | * the maximum cache ticks to cache the nearby NPC 'flock' (default 30) 32 | */ 33 | public RadiusNPCFlock(double radius, int maxCacheTicks) { 34 | this.radius = radius; 35 | this.maxCacheTicks = maxCacheTicks; 36 | } 37 | 38 | @Override 39 | public Collection getNearby(NPC npc) { 40 | if (cached != null && cacheTicks++ < maxCacheTicks) 41 | return cached; 42 | cached = null; 43 | cacheTicks = 0; 44 | Collection ret = Lists.newArrayList(); 45 | for (NPC npc2 : CitizensAPI.getLocationLookup().getNearbyNPCs(npc.getEntity().getLocation(), radius)) { 46 | if (npc2.getNavigator().isNavigating()) { 47 | ret.add(npc2); 48 | } 49 | } 50 | if (maxCacheTicks <= 0) 51 | return ret; 52 | return this.cached = ret; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/StatusMapper.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * Wraps an {@link Behavior} and returns a supplied {@link BehaviorStatus} instead of the underlying status. 7 | */ 8 | public class StatusMapper extends BehaviorGoalAdapter { 9 | private final Supplier to; 10 | private final Behavior wrapping; 11 | 12 | private StatusMapper(Behavior wrapping, Supplier to) { 13 | this.wrapping = wrapping; 14 | this.to = to; 15 | } 16 | 17 | @Override 18 | public void reset() { 19 | wrapping.reset(); 20 | } 21 | 22 | @Override 23 | public BehaviorStatus run() { 24 | return to.get(); 25 | } 26 | 27 | @Override 28 | public boolean shouldExecute() { 29 | return wrapping.shouldExecute(); 30 | } 31 | 32 | public static StatusMapper mapping(Behavior wrapping, Supplier to) { 33 | return new StatusMapper(wrapping, to); 34 | } 35 | 36 | public static Behavior singleUse(Behavior base) { 37 | return new Behavior() { 38 | @Override 39 | public void reset() { 40 | base.reset(); 41 | } 42 | 43 | @Override 44 | public BehaviorStatus run() { 45 | BehaviorStatus status = base.run(); 46 | switch (status) { 47 | case FAILURE: 48 | case SUCCESS: 49 | return BehaviorStatus.RESET_AND_REMOVE; 50 | default: 51 | return status; 52 | } 53 | } 54 | 55 | @Override 56 | public boolean shouldExecute() { 57 | return base.shouldExecute(); 58 | } 59 | }; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/CommandSenderCreateNPCEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.npc.NPC; 8 | 9 | public class CommandSenderCreateNPCEvent extends NPCCreateEvent implements Cancellable { 10 | private boolean cancelled; 11 | private final CommandSender creator; 12 | private String reason; 13 | 14 | public CommandSenderCreateNPCEvent(CommandSender sender, NPC npc) { 15 | super(npc); 16 | creator = sender; 17 | } 18 | 19 | /** 20 | * @return The reason for cancelling the event 21 | * @see #getCancelReason() 22 | */ 23 | public String getCancelReason() { 24 | return reason; 25 | } 26 | 27 | /** 28 | * @return The {@link CommandSender} creating the NPC. 29 | */ 30 | public CommandSender getCreator() { 31 | return creator; 32 | } 33 | 34 | @Override 35 | public HandlerList getHandlers() { 36 | return handlers; 37 | } 38 | 39 | @Override 40 | public boolean isCancelled() { 41 | return cancelled; 42 | } 43 | 44 | @Override 45 | public void setCancelled(boolean cancel) { 46 | cancelled = cancel; 47 | } 48 | 49 | /** 50 | * Sets the reason for cancelling the event. This will be sent to the {@link CommandSender} creator to explain why 51 | * the NPC cannot be created. 52 | * 53 | * @param reason 54 | * The reason explaining the cancellation 55 | */ 56 | public void setCancelReason(String reason) { 57 | this.reason = reason; 58 | } 59 | 60 | public static HandlerList getHandlerList() { 61 | return handlers; 62 | } 63 | 64 | private static final HandlerList handlers = new HandlerList(); 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/trait/MobType.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait.trait; 2 | 3 | import org.bukkit.entity.EntityType; 4 | 5 | import net.citizensnpcs.api.trait.Trait; 6 | import net.citizensnpcs.api.trait.TraitName; 7 | import net.citizensnpcs.api.util.DataKey; 8 | 9 | /** 10 | * Represents an NPC's mob type. 11 | */ 12 | @TraitName("type") 13 | public class MobType extends Trait { 14 | private EntityType type = EntityType.PLAYER; 15 | 16 | public MobType() { 17 | super("type"); 18 | } 19 | 20 | /** 21 | * Gets the type of mob that an NPC is. 22 | * 23 | * @return The mob type 24 | */ 25 | public EntityType getType() { 26 | return type; 27 | } 28 | 29 | @Override 30 | public void load(DataKey key) { 31 | try { 32 | if (key.getString("").equals("PIG_ZOMBIE")) { 33 | type = EntityType.ZOMBIFIED_PIGLIN; 34 | } else { 35 | type = EntityType.valueOf(key.getString("")); 36 | } 37 | } catch (IllegalArgumentException ex) { 38 | type = EntityType.fromName(key.getString("")); 39 | } 40 | if (type == null) { 41 | type = EntityType.PLAYER; 42 | } 43 | npc.setBukkitEntityType(type); 44 | } 45 | 46 | @Override 47 | public void onSpawn() { 48 | type = npc.getEntity().getType(); 49 | } 50 | 51 | @Override 52 | public void save(DataKey key) { 53 | key.setString("", type.name()); 54 | } 55 | 56 | /** 57 | * Sets the type of mob that an NPC is. 58 | * 59 | * @param type 60 | * Mob type to set the NPC as 61 | */ 62 | public void setType(EntityType type) { 63 | this.type = type; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "MobType{" + type + "}"; 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/PersisterRegistry.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import java.lang.ref.WeakReference; 4 | import java.util.Map; 5 | 6 | import com.google.common.collect.Iterables; 7 | import com.google.common.collect.Maps; 8 | 9 | import net.citizensnpcs.api.util.DataKey; 10 | 11 | /** 12 | * A stringly-typed registry that loads and saves its types using {@link PersistenceLoader} and {@link DataKey}s. 13 | **/ 14 | public class PersisterRegistry implements Persister { 15 | private final Map>> registry = Maps.newHashMap(); 16 | 17 | PersisterRegistry() { 18 | } 19 | 20 | @Override 21 | public T create(DataKey root) { 22 | String type = root.getString("type"); 23 | WeakReference> clazz = registry.get(type); 24 | if (clazz == null) 25 | throw new IllegalStateException("missing registration for type " + type); 26 | return PersistenceLoader.load(clazz.get(), root); 27 | } 28 | 29 | public void register(String type, Class clazz) { 30 | registry.put(type, new WeakReference<>(clazz)); 31 | } 32 | 33 | public Iterable> registeredTypes() { 34 | return Iterables.transform(registry.values(), WeakReference::get); 35 | } 36 | 37 | @Override 38 | public void save(T instance, DataKey root) { 39 | PersistenceLoader.save(instance, root); 40 | Class clazz = instance.getClass(); 41 | for (Map.Entry>> entry : registry.entrySet()) { 42 | if (clazz == entry.getValue().get()) { 43 | root.setString("type", entry.getKey()); 44 | return; 45 | } 46 | } 47 | throw new IllegalStateException("missing registration for instance " + instance); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/command/CommandMessages.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.command; 2 | 3 | public class CommandMessages { 4 | public static final String COMMAND_HELP_HEADER = "citizens.commands.help.header"; 5 | public static final String COMMAND_MISSING = "citizens.commands.help.command-missing"; 6 | public static final String COMMAND_PAGE_MISSING = "citizens.commands.page-missing"; 7 | public static final String ID_NOT_FOUND = "citizens.commands.id-not-found"; 8 | public static final String INVALID_LOCATION = "citizens.commands.npc.create.invalid-location"; 9 | public static final String INVALID_NUMBER = "citizens.commands.invalid-number"; 10 | public static final String MISSING_TRAIT = "citizens.commands.requirements.missing-required-trait"; 11 | public static final String MUST_BE_INGAME = "citizens.commands.requirements.must-be-ingame"; 12 | public static final String MUST_BE_OWNER = "citizens.commands.requirements.must-be-owner"; 13 | public static final String MUST_HAVE_SELECTED = "citizens.commands.requirements.must-have-selected"; 14 | public static final String NO_PERMISSION = "citizens.commands.requirements.missing-permission"; 15 | public static final String PLAYER_NOT_FOUND_FOR_SPAWN = "citizens.commands.npc.create.no-player-for-spawn"; 16 | public static final String REPORT_ERROR = "citizens.commands.console-error"; 17 | public static final String REQUIREMENTS_INVALID_MOB_TYPE = "citizens.commands.requirements.disallowed-mobtype"; 18 | public static final String REQUIREMENTS_MUST_BE_LIVING_ENTITY = "citizens.commands.requirements.living-entity"; 19 | public static final String TOO_FEW_ARGUMENTS = "citizens.commands.requirements.too-few-arguments"; 20 | public static final String TOO_MANY_ARGUMENTS = "citizens.commands.requirements.too-many-arguments"; 21 | public static final String UNKNOWN_COMMAND = "citizens.commands.unknown-command"; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/hpastar/HPAGraphNode.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.hpastar; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class HPAGraphNode { 8 | final List> edges = new ArrayList<>(); 9 | final int x; 10 | final int y; 11 | final int z; 12 | 13 | public HPAGraphNode(int x, int y, int z) { 14 | this.x = x; 15 | this.y = y; 16 | this.z = z; 17 | } 18 | 19 | public void connect(int level, HPAGraphNode to, HPAGraphEdge.EdgeType type, float weight) { 20 | while (level >= edges.size()) { 21 | edges.add(new ArrayList<>()); 22 | } 23 | while (level >= to.edges.size()) { 24 | to.edges.add(new ArrayList<>()); 25 | } 26 | edges.get(level).add(new HPAGraphEdge(this, to, type, weight)); 27 | to.edges.get(level).add(new HPAGraphEdge(to, this, type, weight)); 28 | } 29 | 30 | public double distance(HPAGraphNode dest) { 31 | return Math.sqrt(Math.pow(x - dest.x, 2) + Math.pow(y - dest.y, 2) + Math.pow(z - dest.z, 2)); 32 | } 33 | 34 | @Override 35 | public boolean equals(Object obj) { 36 | if (this == obj) 37 | return true; 38 | if (obj == null || getClass() != obj.getClass()) 39 | return false; 40 | HPAGraphNode other = (HPAGraphNode) obj; 41 | if (x != other.x || y != other.y || z != other.z) 42 | return false; 43 | return true; 44 | } 45 | 46 | public List getEdges(int level) { 47 | if (level >= edges.size()) 48 | return Collections.emptyList(); 49 | return edges.get(level); 50 | } 51 | 52 | @Override 53 | public int hashCode() { 54 | return 31 * (31 * (31 + x) + y) + z; 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return x + "," + y + "," + z; 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/NPCDataStore.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc; 2 | 3 | public interface NPCDataStore { 4 | /** 5 | * Clears all data about the given {@link NPC} from storage. Called when the NPC is removed. 6 | * 7 | * @param npc 8 | * The NPC to clear data from 9 | */ 10 | void clearData(NPC npc); 11 | 12 | /** 13 | * Clears all trait data from all NPCs from the given list of names. 14 | */ 15 | void clearTraitData(Iterable traitNames); 16 | 17 | /** 18 | * @param registry 19 | * The registry for the unique ID. 20 | * @return An ID for a new NPC to identify them uniquely 21 | */ 22 | int createUniqueNPCId(NPCRegistry registry); 23 | 24 | /** 25 | * Loads NPCs from disk into the given {@link NPCRegistry}. The registry should be cleared before this is called. 26 | * 27 | * @param registry 28 | * The NPCRegistry to load NPCs into 29 | */ 30 | void loadInto(NPCRegistry registry); 31 | 32 | /** 33 | * Reloads the data store from source (such as a file on disk). 34 | */ 35 | void reloadFromSource(); 36 | 37 | /** 38 | * Notifies the data store to save all stored data to disk. May be asynchronous. 39 | */ 40 | void saveToDisk(); 41 | 42 | /** 43 | * Notifies the data store to save all stored data to disk immediately. Must not be asynchronous. 44 | */ 45 | void saveToDiskImmediate(); 46 | 47 | /** 48 | * Stores the given {@link NPC} into memory or to a disk representation. 49 | * 50 | * @param npc 51 | * The NPC to store 52 | */ 53 | void store(NPC npc); 54 | 55 | /** 56 | * Stores all {@link NPC}s in the given {@link NPCRegistry} to disk. 57 | * 58 | * @param registry 59 | * The registry to store NPCs from 60 | */ 61 | void storeAll(NPCRegistry registry); 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/SimpleGoalEntry.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai; 2 | 3 | import java.util.Objects; 4 | import java.util.function.Supplier; 5 | 6 | import net.citizensnpcs.api.ai.GoalController.GoalEntry; 7 | import net.citizensnpcs.api.ai.tree.Behavior; 8 | import net.citizensnpcs.api.ai.tree.ForwardingBehaviorGoalAdapter; 9 | 10 | public class SimpleGoalEntry implements GoalEntry { 11 | private final Goal goal; 12 | private final Supplier priority; 13 | 14 | public SimpleGoalEntry(Goal goal, int priority) { 15 | this(goal, () -> priority); 16 | } 17 | 18 | public SimpleGoalEntry(Goal goal, Supplier priority) { 19 | this.goal = goal; 20 | this.priority = priority; 21 | } 22 | 23 | @Override 24 | public int compareTo(GoalEntry o) { 25 | return Integer.compare(getPriority(), o.getPriority()); 26 | } 27 | 28 | @Override 29 | public boolean equals(Object obj) { 30 | if (this == obj) 31 | return true; 32 | if (obj == null || getClass() != obj.getClass()) 33 | return false; 34 | SimpleGoalEntry other = (SimpleGoalEntry) obj; 35 | if (!Objects.equals(goal, other.goal)) 36 | return false; 37 | return priority == other.priority; 38 | } 39 | 40 | @Override 41 | public Behavior getBehavior() { 42 | return goal instanceof Behavior ? (Behavior) goal 43 | : goal instanceof ForwardingBehaviorGoalAdapter ? ((ForwardingBehaviorGoalAdapter) goal).getWrapped() 44 | : null; 45 | } 46 | 47 | @Override 48 | public Goal getGoal() { 49 | return goal; 50 | } 51 | 52 | @Override 53 | public int getPriority() { 54 | return priority.get(); 55 | } 56 | 57 | @Override 58 | public int hashCode() { 59 | final int prime = 31; 60 | return prime * (prime + (goal == null ? 0 : goal.hashCode())) + priority.get(); 61 | } 62 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/Behavior.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import net.citizensnpcs.api.ai.Goal; 4 | 5 | /** 6 | * The base class for the second iteration of the {@link Goal} API, which can be made backwards compatible by extending 7 | * {@link BehaviorGoalAdapter}. 8 | *

9 | * A behavior is a common term for the parts of a behavior tree, which is a simple directed acyclic graph (DAG) 10 | * for AI. It is a simple state machine using {@link BehaviorStatus}. 11 | *

12 | * Nodes are executed in a top-down fashion through the tree. For legacy reasons, the tree is executed as a number of 13 | * executing nodes which are transitioned between using the {@link BehaviorStatus} they return. 14 | *

15 | * New child nodes are selected to become executing nodes based on {@link Behavior#shouldExecute()}. The 16 | * selection behavior can vary, e.g. running a list of nodes using {@link Sequence} or choosing from children nodes 17 | * using {@link Selector}. The executing nodes are repeatedly {@link Behavior#run()} until the return result changes 18 | * from {@link BehaviorStatus#RUNNING}. 19 | * 20 | * @see https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control) 22 | */ 23 | public interface Behavior { 24 | /** 25 | * Resets the behavior and any state it is holding. 26 | */ 27 | void reset(); 28 | 29 | /** 30 | * Runs the behavior for one 'tick', optionally changing the state that it is in. 31 | * 32 | * @return The new state 33 | */ 34 | BehaviorStatus run(); 35 | 36 | /** 37 | * Returns whether the behavior is ready to run. Note this is called once when deciding whether to start 38 | * execution of a leaf node. The actual execution status is determined by the return value of {@link Behavior#run()} 39 | * which is repeatedly called by the executing node. 40 | */ 41 | boolean shouldExecute(); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/SimpleAStarStorage.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.PriorityQueue; 6 | import java.util.Queue; 7 | import java.util.function.Supplier; 8 | 9 | import com.google.common.collect.Maps; 10 | 11 | /** 12 | * A base implementation of {@link AStarStorage} that uses a {@link PriorityQueue} for the frontier and {@link HashMap}s 13 | * for the open/closed sets. 14 | */ 15 | public class SimpleAStarStorage implements AStarStorage { 16 | private final Map closed = Maps.newHashMapWithExpectedSize(512); 17 | private final Map open = Maps.newHashMapWithExpectedSize(128); 18 | private final Queue queue = new PriorityQueue<>(128); 19 | 20 | @Override 21 | public void close(AStarNode node) { 22 | open.remove(node); 23 | closed.put(node, node.g); 24 | } 25 | 26 | @Override 27 | public AStarNode getBestNode() { 28 | return queue.peek(); 29 | } 30 | 31 | @Override 32 | public void open(AStarNode node) { 33 | queue.offer(node); 34 | open.put(node, node.g); 35 | closed.remove(node); 36 | } 37 | 38 | @Override 39 | public AStarNode removeBestNode() { 40 | return queue.poll(); 41 | } 42 | 43 | @Override 44 | public boolean shouldExamine(AStarNode neighbour) { 45 | Float openG = open.get(neighbour); 46 | if (openG != null && openG > neighbour.g) { 47 | open.remove(neighbour); 48 | openG = null; 49 | } 50 | Float closedG = closed.get(neighbour); 51 | if (closedG != null && closedG > neighbour.g) { 52 | closed.remove(neighbour); 53 | closedG = null; 54 | } 55 | return closedG == null && openG == null; 56 | } 57 | 58 | @Override 59 | public String toString() { 60 | return "SimpleAStarStorage [closed=" + closed + ", open=" + open + "]"; 61 | } 62 | 63 | public static final Supplier FACTORY = SimpleAStarStorage::new; 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/event/NPCMoveEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.event; 2 | 3 | import java.util.Objects; 4 | 5 | import org.bukkit.Location; 6 | import org.bukkit.event.Cancellable; 7 | import org.bukkit.event.Event; 8 | import org.bukkit.event.HandlerList; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import net.citizensnpcs.api.npc.NPC; 12 | 13 | public class NPCMoveEvent extends Event implements Cancellable { 14 | private boolean cancelled; 15 | 16 | private Location from; 17 | private final NPC npc; 18 | private Location to; 19 | 20 | public NPCMoveEvent(NPC npc, Location from, Location to) { 21 | this.npc = npc; 22 | this.from = from; 23 | this.to = to; 24 | } 25 | 26 | public Location getFrom() { 27 | return from; 28 | } 29 | 30 | @NotNull 31 | @Override 32 | public HandlerList getHandlers() { 33 | return handlers; 34 | } 35 | 36 | public NPC getNPC() { 37 | return npc; 38 | } 39 | 40 | public Location getTo() { 41 | return to; 42 | } 43 | 44 | @Override 45 | public boolean isCancelled() { 46 | return cancelled; 47 | } 48 | 49 | @Override 50 | public void setCancelled(boolean b) { 51 | this.cancelled = b; 52 | } 53 | 54 | public void setFrom(Location from) { 55 | Objects.requireNonNull(from, "from cannot be null"); 56 | Objects.requireNonNull(from.getWorld(), "from.getWorld() cannot be null"); 57 | this.from = from; 58 | } 59 | 60 | public void setTo(Location to) { 61 | Objects.requireNonNull(to, "to cannot be null"); 62 | Objects.requireNonNull(to.getWorld(), "to.getWorld() cannot be null"); 63 | this.to = to; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "NPCMoveEvent{" + "npc=" + npc + ", from=" + from + ", to=" + to + ", cancelled=" + cancelled + '}'; 69 | } 70 | 71 | public static HandlerList getHandlerList() { 72 | return handlers; 73 | } 74 | 75 | private static final HandlerList handlers = new HandlerList(); 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/trait/TraitFactory.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.trait; 2 | 3 | import java.util.Collection; 4 | 5 | import net.citizensnpcs.api.npc.NPC; 6 | 7 | public interface TraitFactory { 8 | /** 9 | * Adds all default traits to a given NPC. 10 | * 11 | * @param npc 12 | * The NPC to add default traits to 13 | */ 14 | void addDefaultTraits(NPC npc); 15 | 16 | /** 17 | * Removes a trait. This prevents a trait from being added to an NPC but does not remove existing traits from the 18 | * NPCs. 19 | * 20 | * @param info 21 | * The TraitInfo to deregister 22 | */ 23 | void deregisterTrait(TraitInfo info); 24 | 25 | /** 26 | * @return All currently registered traits, including internal traits. 27 | */ 28 | Collection getRegisteredTraits(); 29 | 30 | /** 31 | * Gets the {@link TraitTemplateParser} with the given trait name or null if not found. 32 | * 33 | * @param name 34 | * @return the trait template parser 35 | */ 36 | TraitTemplateParser getTemplateParser(String name); 37 | 38 | /** 39 | * Gets a trait with the given class. 40 | * 41 | * @param clazz 42 | * Class of the trait 43 | * @return Trait with the given class 44 | */ 45 | T getTrait(Class clazz); 46 | 47 | /** 48 | * Gets a trait with the given name. 49 | * 50 | * @param name 51 | * Name of the trait 52 | * @return Trait with the given name 53 | */ 54 | T getTrait(String name); 55 | 56 | /** 57 | * Gets the {@link Trait} class with the given name, or null if not found. 58 | * 59 | * @param name 60 | * The trait name 61 | * @return The trait class 62 | */ 63 | Class getTraitClass(String name); 64 | 65 | /** 66 | * Registers a trait using the given information. 67 | * 68 | * @param info 69 | * Registration information 70 | */ 71 | void registerTrait(TraitInfo info); 72 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/gui/MenuContext.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.gui; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | 6 | import org.bukkit.inventory.Inventory; 7 | 8 | import com.google.common.collect.Maps; 9 | 10 | import net.citizensnpcs.api.util.Messaging; 11 | 12 | /** 13 | * A context class passed into the constructor of a {@link Menu} instance. 14 | */ 15 | public class MenuContext { 16 | private final Map data = Maps.newHashMap(); 17 | private final Inventory inventory; 18 | private final InventoryMenu menu; 19 | private final InventoryMenuSlot[] slots; 20 | private String title; 21 | 22 | public MenuContext(InventoryMenu menu, InventoryMenuSlot[] slots, Inventory inventory, String title) { 23 | this(menu, slots, inventory, title, Collections.emptyMap()); 24 | } 25 | 26 | public MenuContext(InventoryMenu menu, InventoryMenuSlot[] slots, Inventory inventory, String title, 27 | Map data) { 28 | this.inventory = inventory; 29 | this.title = title; 30 | this.slots = slots; 31 | this.menu = menu; 32 | this.data.putAll(data); 33 | } 34 | 35 | public void clearSlots() { 36 | for (int i = 0; i < slots.length; i++) { 37 | InventoryMenuSlot slot = slots[i]; 38 | if (slot != null) { 39 | slot.clear(); 40 | } 41 | slots[i] = null; 42 | } 43 | } 44 | 45 | public Map data() { 46 | return data; 47 | } 48 | 49 | public Inventory getInventory() { 50 | return inventory; 51 | } 52 | 53 | public InventoryMenu getMenu() { 54 | return menu; 55 | } 56 | 57 | public InventoryMenuSlot getSlot(int i) { 58 | if (slots[i] == null) 59 | return slots[i] = new InventoryMenuSlot(this, i); 60 | return slots[i]; 61 | } 62 | 63 | public String getTitle() { 64 | return title; 65 | } 66 | 67 | public void setTitle(String title) { 68 | this.title = Messaging.parseComponents(title); 69 | this.menu.updateTitle(title); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/goals/FollowPathGoal.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.goals; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | import org.bukkit.Location; 7 | 8 | import net.citizensnpcs.api.ai.Goal; 9 | import net.citizensnpcs.api.ai.tree.Behavior; 10 | import net.citizensnpcs.api.ai.tree.BehaviorGoalAdapter; 11 | import net.citizensnpcs.api.ai.tree.BehaviorStatus; 12 | import net.citizensnpcs.api.npc.NPC; 13 | 14 | /** 15 | * A sample {@link Goal}/{@link Behavior} that simply moves an {@link NPC} through a list of {@link Location}s. 16 | */ 17 | public class FollowPathGoal extends BehaviorGoalAdapter { 18 | private int idx; 19 | private final NPC npc; 20 | private final List path; 21 | 22 | public FollowPathGoal(NPC npc, List path) { 23 | this.npc = npc; 24 | this.path = path; 25 | } 26 | 27 | @Override 28 | public void reset() { 29 | npc.getNavigator().cancelNavigation(); 30 | idx = 0; 31 | } 32 | 33 | @Override 34 | public BehaviorStatus run() { 35 | if (idx >= path.size()) 36 | return BehaviorStatus.SUCCESS; 37 | if (!npc.getNavigator().isNavigating()) { 38 | setPath(); 39 | } 40 | BehaviorStatus status = path.get(idx).run(); 41 | if (status == BehaviorStatus.SUCCESS) { 42 | idx++; 43 | setPath(); 44 | return BehaviorStatus.RUNNING; 45 | } 46 | return status; 47 | } 48 | 49 | private void setPath() { 50 | if (idx >= path.size()) 51 | return; 52 | path.get(idx).shouldExecute(); 53 | } 54 | 55 | @Override 56 | public boolean shouldExecute() { 57 | return !npc.getNavigator().isNavigating() && path != null; 58 | } 59 | 60 | public static FollowPathGoal create(NPC npc, List path) { 61 | return new FollowPathGoal(npc, path); 62 | } 63 | 64 | public static FollowPathGoal createFromLocations(NPC npc, List path) { 65 | return new FollowPathGoal(npc, path.stream().map(loc -> new MoveToGoal(npc, loc)).collect(Collectors.toList())); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/ChunkBlockSource.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import org.bukkit.Chunk; 4 | import org.bukkit.Location; 5 | import org.bukkit.Material; 6 | import org.bukkit.World; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.block.data.BlockData; 9 | 10 | import net.citizensnpcs.api.util.BoundingBox; 11 | 12 | public class ChunkBlockSource extends CachingChunkBlockSource { 13 | public ChunkBlockSource(Location location, float radius) { 14 | super(location, radius); 15 | } 16 | 17 | public ChunkBlockSource(World world, int x, int z, float radius) { 18 | super(world, x, z, radius); 19 | } 20 | 21 | @Override 22 | protected BlockData getBlockData(Chunk chunk, int x, int y, int z) { 23 | return chunk.getBlock(x & 15, y, z & 15).getBlockData(); 24 | } 25 | 26 | @Override 27 | protected Chunk getChunkObject(int x, int z) { 28 | return world.getChunkAt(x, z); 29 | } 30 | 31 | @Override 32 | protected BoundingBox getCollisionBox(Chunk chunk, int x, int y, int z) { 33 | if (!SUPPORT_BOUNDING_BOX) 34 | return null; 35 | return BoundingBox.convert(world.getBlockAt(x, y, z).getBoundingBox()); 36 | } 37 | 38 | @Override 39 | protected int getLightLevel(Chunk chunk, int x, int y, int z) { 40 | return chunk.getBlock(x, y, z).getLightLevel(); 41 | } 42 | 43 | @Override 44 | protected Material getType(Chunk chunk, int x, int y, int z) { 45 | return SUPPORT_GET_TYPE ? world.getType(x, y, z) : chunk.getBlock(x & 15, y, z & 15).getType(); 46 | } 47 | 48 | private static boolean SUPPORT_BOUNDING_BOX = true; 49 | private static boolean SUPPORT_GET_TYPE = true; 50 | static { 51 | try { 52 | Class.forName("org.bukkit.RegionAccessor").getMethod("getType", int.class, int.class, int.class); 53 | } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) { 54 | SUPPORT_GET_TYPE = false; 55 | } 56 | try { 57 | Block.class.getMethod("getBoundingBox"); 58 | } catch (NoSuchMethodException | SecurityException e) { 59 | SUPPORT_BOUNDING_BOX = false; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/astar/pathfinder/PathPoint.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.astar.pathfinder; 2 | 3 | import java.util.List; 4 | 5 | import org.bukkit.block.Block; 6 | import org.bukkit.util.Vector; 7 | 8 | import net.citizensnpcs.api.npc.NPC; 9 | 10 | public interface PathPoint { 11 | /** 12 | * Adds a path callback that will be executed if this path point is executed. 13 | */ 14 | void addCallback(PathCallback callback); 15 | 16 | /** 17 | * Returns a new PathPoint at a given Vector. 18 | */ 19 | PathPoint createAtOffset(Vector vector); 20 | 21 | /** 22 | * Gets the destination Vector 23 | */ 24 | Vector getGoal(); 25 | 26 | /** 27 | * Gets the parent PathPoint 28 | */ 29 | PathPoint getParentPoint(); 30 | 31 | /** 32 | * Gets the list of manual path vectors 33 | * 34 | * @see #setPathVectors(List) 35 | */ 36 | List getPathVectors(); 37 | 38 | /** 39 | * Gets the vector represented by this point 40 | */ 41 | Vector getVector(); 42 | 43 | /** 44 | * Sets the path vectors that will be used at pathfinding time. For example, setting a list of vectors to path 45 | * through in order to reach this pathpoint. 46 | */ 47 | void setPathVectors(List vectors); 48 | 49 | /** 50 | * Sets the vector location of this point 51 | */ 52 | void setVector(Vector vector); 53 | 54 | public static interface PathCallback { 55 | /** 56 | * Run once the specificed point is reached. 57 | * 58 | * @param npc 59 | * The NPC 60 | * @param point 61 | * The point that was reached 62 | */ 63 | default void onReached(NPC npc, Block point) { 64 | } 65 | 66 | /** 67 | * Run every tick when moving towards a specific block. 68 | * 69 | * @param npc 70 | * The NPC 71 | * @param point 72 | * The point 73 | * @param path 74 | * The future path destinations as blocks 75 | * @param index 76 | * The current path index 77 | */ 78 | void run(NPC npc, Block point, List path, int index); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/npc/templates/CommandEventAction.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.npc.templates; 2 | 3 | import java.lang.invoke.MethodHandle; 4 | import java.lang.invoke.MethodHandles; 5 | import java.lang.invoke.MethodType; 6 | import java.util.Set; 7 | import java.util.UUID; 8 | import java.util.function.Consumer; 9 | 10 | import org.bukkit.event.EventPriority; 11 | import org.bukkit.event.HandlerList; 12 | import org.bukkit.event.Listener; 13 | import org.bukkit.plugin.RegisteredListener; 14 | 15 | import com.google.common.collect.Sets; 16 | 17 | import net.citizensnpcs.api.CitizensAPI; 18 | import net.citizensnpcs.api.event.NPCEvent; 19 | import net.citizensnpcs.api.npc.NPC; 20 | import net.citizensnpcs.api.util.Messaging; 21 | 22 | public class CommandEventAction implements Consumer { 23 | private final Set uuids = Sets.newHashSet(); 24 | 25 | public CommandEventAction(Class clazz, Consumer commands) { 26 | try { 27 | HandlerList handlers = (HandlerList) clazz.getMethod("getHandlerList").invoke(null); 28 | handlers.register(new RegisteredListener(new Listener() { 29 | }, (listener, event) -> { 30 | try { 31 | if (event.getClass() != clazz) 32 | return; 33 | NPC npc = (NPC) GET_NPC.invoke(event); 34 | if (uuids.contains(npc.getUniqueId())) { 35 | commands.accept(npc); 36 | } 37 | } catch (Throwable ex) { 38 | ex.printStackTrace(); 39 | } 40 | }, EventPriority.NORMAL, CitizensAPI.getPlugin(), true)); 41 | } catch (Throwable ex) { 42 | Messaging.severe("Error registering template event listener"); 43 | ex.printStackTrace(); 44 | } 45 | } 46 | 47 | @Override 48 | public void accept(NPC npc) { 49 | uuids.add(npc.getUniqueId()); 50 | } 51 | 52 | private static MethodHandle GET_NPC = null; 53 | static { 54 | try { 55 | GET_NPC = MethodHandles.publicLookup().findVirtual(NPCEvent.class, "getNPC", 56 | MethodType.methodType(NPC.class)); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/speech/event/SpeechEvent.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.speech.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | 7 | import net.citizensnpcs.api.ai.speech.SpeechContext; 8 | import net.citizensnpcs.api.ai.speech.Talkable; 9 | 10 | /** 11 | * Represents an event where a {@link Talkable} entity speaks at/near a {@link Talkable} entity. 12 | * 13 | */ 14 | public class SpeechEvent extends Event implements Cancellable { 15 | private boolean cancelled = false; 16 | SpeechContext context; 17 | String message; 18 | Talkable target; 19 | 20 | public SpeechEvent(Talkable target, SpeechContext context, String message) { 21 | this.target = target; 22 | this.context = context; 23 | this.message = message; 24 | } 25 | 26 | /** 27 | * Gets the {@link SpeechContext} associated with the SpeechEvent. 28 | * 29 | * @return the SpeechContext 30 | */ 31 | public SpeechContext getContext() { 32 | return context; 33 | } 34 | 35 | @Override 36 | public HandlerList getHandlers() { 37 | return handlers; 38 | } 39 | 40 | /** 41 | * The final message to be sent to the bystander. Note: This may differ from the message contained in the 42 | * SpeechContext, as formatting may have occurred. 43 | * 44 | * @return the message to be sent to the {@link Talkable} bystander. 45 | */ 46 | public String getMessage() { 47 | return message; 48 | } 49 | 50 | @Override 51 | public boolean isCancelled() { 52 | return cancelled; 53 | } 54 | 55 | @Override 56 | public void setCancelled(boolean cancelled) { 57 | this.cancelled = cancelled; 58 | } 59 | 60 | /** 61 | * Sets the message to be sent to the bystander. Note: This may differ from the message contained in the 62 | * SpeechContext, as formatting may have occurred. 63 | */ 64 | public void setMessage(String formattedMessage) { 65 | this.message = formattedMessage; 66 | } 67 | 68 | public static HandlerList getHandlerList() { 69 | return handlers; 70 | } 71 | 72 | private static final HandlerList handlers = new HandlerList(); 73 | } -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/persistence/Persist.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.persistence; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.util.Collection; 8 | 9 | import net.citizensnpcs.api.util.DataKey; 10 | 11 | /** 12 | * A marker annotation for {@link PersistenceLoader} to persist a field by saving and loading it into {@link DataKey}s. 13 | */ 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target(ElementType.FIELD) 16 | public @interface Persist { 17 | /** 18 | * The specialised collection type to use when a super class is specified. Eg. WeakHashMap.class when the field type 19 | * is Map. 20 | */ 21 | Class collectionType() default Collection.class; 22 | 23 | /** 24 | * The specific key type to use when deserialising Map keys from storage. Only supports primitive values and UUIDs 25 | * currently. 26 | */ 27 | Class keyType() default String.class; 28 | 29 | /** 30 | * If using global/static persistence, must be non-empty. 31 | */ 32 | String namespace() default ""; 33 | 34 | /** 35 | * Whether to use PersistenceLoader to load/save the value of this class. 36 | */ 37 | boolean reify() default false; 38 | 39 | /** 40 | * Whether a value must be present at load time. If a value for the field could not be loaded, 41 | * {@link PersistenceLoader#load(Object, DataKey)} will return null. 42 | */ 43 | boolean required() default false; 44 | 45 | /** 46 | * The DataKey path to use when saving/loading. If not present, the field name will be used instead. 47 | * 48 | *

    49 | *
  • @Persist -> root key + field name
  • 50 | *
  • @Persist("") -> root key + "" (i.e. just the root key)
  • 51 | *
  • @Persist("sub") root key + "sub"
  • 52 | *
  • @Persist("$key") loads the root key, does not save
  • 53 | *
54 | */ 55 | String value() default "UNINITIALISED"; 56 | 57 | /** 58 | * The specific value type to use when deserialising values from storage. Most useful when using specific number 59 | * types e.g. Long, Byte, Short but storing as Integer. 60 | */ 61 | Class valueType() default Object.class; 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/tree/Selectors.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.tree; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | import java.util.Comparator; 6 | import java.util.List; 7 | import java.util.function.Function; 8 | 9 | import com.google.common.base.Preconditions; 10 | 11 | /** 12 | * Static helper class for creating common {@link Selector}s. 13 | */ 14 | public class Selectors { 15 | private Selectors() { 16 | } 17 | 18 | public static final class PrioritySelection implements Function, Behavior> { 19 | private final Comparator comparator; 20 | 21 | private PrioritySelection(Comparator comparator) { 22 | this.comparator = comparator; 23 | } 24 | 25 | @Override 26 | public Behavior apply(List input) { 27 | input.sort(comparator); 28 | return input.get(input.size() - 1); 29 | } 30 | } 31 | 32 | /** 33 | * Returns a default priority selection function that assumes the input {@link Behavior}s implement 34 | * {@link Comparable}. 35 | */ 36 | public static Function, Behavior> prioritySelectionFunction() { 37 | return new PrioritySelection(BEHAVIOR_COMPARATOR); 38 | } 39 | 40 | /** 41 | * @see #prioritySelector(Comparator, Collection) 42 | */ 43 | public static Selector.Builder prioritySelector(Comparator comparator, Behavior... behaviors) { 44 | return prioritySelector(comparator, Arrays.asList(behaviors)); 45 | } 46 | 47 | /** 48 | * Builds a {@link Selector} that prioritises certain {@link Behavior}s based on a comparison function. 49 | * 50 | * @param comparator 51 | * The comparison function 52 | * @param behaviors 53 | * The behaviors to select from 54 | */ 55 | public static Selector.Builder prioritySelector(final Comparator comparator, 56 | Collection behaviors) { 57 | if (behaviors.size() > 0) 58 | throw new IllegalArgumentException("must have at least one behavior for comparison"); 59 | return Selector.selecting(behaviors).selectionFunction(new PrioritySelection(comparator)); 60 | } 61 | 62 | private static final Comparator BEHAVIOR_COMPARATOR = (o1, o2) -> ((Comparable) o1) 63 | .compareTo(o2); 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/net/citizensnpcs/api/ai/flocking/Flocker.java: -------------------------------------------------------------------------------- 1 | package net.citizensnpcs.api.ai.flocking; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | import org.bukkit.util.Vector; 8 | 9 | import com.google.common.collect.Collections2; 10 | 11 | import net.citizensnpcs.api.npc.NPC; 12 | import net.citizensnpcs.api.trait.Trait; 13 | 14 | /** 15 | * Implements a simple flocking controller as a {@link Runnable}. This should be run every tick, for example as part of 16 | * an overridden {@link Trait#run}. 17 | * 18 | * @see NPCFlock 19 | * @see FlockBehavior 20 | * @see https://en.wikipedia.org/wiki/Flocking_(behavior) 22 | */ 23 | public class Flocker implements Runnable { 24 | private final List behaviors; 25 | private final NPCFlock flock; 26 | private double maxForce = 1.5; 27 | private final NPC npc; 28 | 29 | public Flocker(NPC npc, NPCFlock flock, FlockBehavior... behaviors) { 30 | this.npc = npc; 31 | this.flock = flock; 32 | this.behaviors = Arrays.asList(behaviors); 33 | } 34 | 35 | @Override 36 | public void run() { 37 | Collection nearby = Collections2.filter(flock.getNearby(npc), NPC::isSpawned); 38 | if (nearby.isEmpty()) 39 | return; 40 | Vector base = new Vector(0, 0, 0); 41 | for (FlockBehavior behavior : behaviors) { 42 | base.add(behavior.getVector(npc, nearby)); 43 | } 44 | base = clip(maxForce, base); 45 | npc.getEntity().setVelocity(npc.getEntity().getVelocity().add(base)); 46 | } 47 | 48 | /** 49 | * Sets the maximum length of the resultant flocking vector. 50 | * 51 | * @param maxForce 52 | * the new maximum length 53 | */ 54 | public void setMaxForce(double maxForce) { 55 | if (maxForce == 0) 56 | throw new IllegalArgumentException(); 57 | this.maxForce = maxForce; 58 | } 59 | 60 | private static Vector clip(double max, Vector vector) { 61 | if (vector.length() > max) 62 | return vector.normalize().multiply(max); 63 | return vector; 64 | } 65 | 66 | /** 67 | * Sample weight indicating high amount of influence from flocking. 68 | */ 69 | public static double HIGH_INFLUENCE = 1.0 / 20.0; 70 | /** 71 | * Sample weight indicating low amount of influence from flocking. 72 | */ 73 | public static double LOW_INFLUENCE = 1.0 / 200.0; 74 | } 75 | --------------------------------------------------------------------------------