API: Difference between revisions

From Citizens Wiki

No edit summary
No edit summary
Line 44: Line 44:


To register a trait, we use the '''TraitFactory''' class. This controls registration for your custom traits.
To register a trait, we use the '''TraitFactory''' class. This controls registration for your custom traits.
{{codebox|height=300px|width=100%|Example registration and simple trait|<syntaxhighlight lang="java5">
{{codebox|height=300px|width=100%|Example registration and simple trait|
//This is your trait that will be applied to a npc using the /trait mytraitname command. Each NPC gets its own instance of this class.
//This is your trait that will be applied to a npc using the /trait mytraitname command. Each NPC gets its own instance of this class.
//the Trait class has a reference to the attached NPC class through the protected field 'npc' or getNPC().
//the Trait class has a reference to the attached NPC class through the protected field 'npc' or getNPC().
Line 138: Line 138:
}
}


</syntaxhighlight>
}}
}}
===Dos and Don'ts===
===Dos and Don'ts===
Line 192: Line 191:
In recent versions of CitizensAPI the "Behavior" class is introduced which allows a behavior tree-based AI approach that is backwards compatible with Goals and GoalControllers.
In recent versions of CitizensAPI the "Behavior" class is introduced which allows a behavior tree-based AI approach that is backwards compatible with Goals and GoalControllers.


{{codebox|height=300px|width=100%|Example|<syntaxhighlight lang="java5">
{{codebox|height=300px|width=100%|Example|
  public class MyGoal implements Goal {
  public class MyGoal implements Goal {
     private Object state;
     private Object state;
Line 217: Line 216:
     }
     }
  }
  }
</syntaxhighlight>
}}
}}


Line 234: Line 232:


Citizens 2.0.4+ provides a simple Persistence API to automatically save and load these variables using DataKeys. The key to this API is the @Persist annotation. Sample code is provided below.
Citizens 2.0.4+ provides a simple Persistence API to automatically save and load these variables using DataKeys. The key to this API is the @Persist annotation. Sample code is provided below.
{{codebox|height=300px|width=100%|Example|<syntaxhighlight lang="java5">
{{codebox|height=300px|width=100%|Example|
  public class MyTrait extends Trait {
  public class MyTrait extends Trait {
     // logic omitted.
     // logic omitted.
Line 244: Line 242:
     @Persist(value="newkey", required=true) String required; // if the value under 'newkey' doesn't exist, then the trait will fail to load.
     @Persist(value="newkey", required=true) String required; // if the value under 'newkey' doesn't exist, then the trait will fail to load.
  }
  }
</syntaxhighlight>}}
}}


More advanced use of the API can be found in the @DelegatePersistence annotation. This allows complex types such as Locations to be saved and loaded with finer grained control. These types can be given default delegates by calling PersistenceLoader#registerPersistDelegate(Persister) - Location has a built in Persister for convenience.
More advanced use of the API can be found in the @DelegatePersistence annotation. This allows complex types such as Locations to be saved and loaded with finer grained control. These types can be given default delegates by calling PersistenceLoader#registerPersistDelegate(Persister) - Location has a built in Persister for convenience.


{{codebox|height=300px|width=100%|Example|<syntaxhighlight lang="java5">
{{codebox|height=300px|width=100%|Example|
  public class MyTrait extends Trait {
  public class MyTrait extends Trait {
     // logic omitted.
     // logic omitted.
Line 271: Line 269:
     }
     }
  }
  }
</syntaxhighlight>}}
}}


==See Also==
==See Also==

Revision as of 14:53, 23 March 2016

Current Release Download: Jenkins

Developmental Builds: Jenkins

Documentation: JavaDocs

Source: Github

Citizens has an extensive API that can be used for making your plugins work with NPCs or even for adding a brand new character that can be attached to an NPC. Make sure you always are using an up-to-date build of the CitizensAPI to ensure that your plugin works with the latest release of Citizens.

Javadocs can be found at http://jd.citizensnpcs.co

Hooking Into Citizens

Hooking into Citizens is as simple as creating a basic plugin and adding the line depend: [Citizens] into your plugin.yml. From here, a common basic entry point is the CitizensAPI class. This gives you access to the NPCRegistry for NPC lookup, as well as the TraitFactory which allows trait registration. If Citizens is not loaded, all CitizensAPI.* methods will return null.

Creating an NPC

The simplest way to create an NPC is to use an NPCRegistry, which manages the storage and creation of NPCs. The default registry is given by CitizensAPI.getNPCRegistry(), and you can create new ones with different storage methods by calling other CitizensAPI methods. A Player NPC with name "fullwall" could then be created like this:

NPC npc = CitizensAPI.getNPCRegistry().createNPC(EntityType.PLAYER, "fullwall");

Checking if an entity is a Citizens NPC

Citizens NPCs will have the "NPC" metadata set to true. Eg.

boolean isCitizensNPC = entity.hasMetadata("NPC");

Creating a Trait

Traits are persistent, attachable objects that are linked to an NPC and provide specific functionality. This can be anything from a full-blown dynamic villager AI to a simple talking trait.

If using Maven, Citizens' Maven repo is available at http://repo.citizensnpcs.co

To register a trait, we use the TraitFactory class. This controls registration for your custom traits.

Code: Example registration and simple trait

Dos and Don'ts

DO

  • Check npc.isSpawned() before using npc.getBukkitEntity()
  • Check npc.isSpawned() before using npc.getNavigator()
  • Create a separate singleton Listener class if you expect there to be many instances of this trait running. This may help performance with frequently called events.
  • Honor npc.data().get(NPC.DEFAULT_PROTECTED_METADATA) If this is true the NPC should be 'invulnerable' to normal damaging effects.
  • use CitizensAPI.getNPCRegistry().isNPC() to check if an entity is a NPC. Real players and player-type NPCs will both return true for instanceof Player.

DON'T

  • Attempt to access npc.getBukkitEntity() from within traits until onSpawn() has been called or npc.isSpawned() returns true.
  • Change anything in npc.getNavigator.getDefaultParams() unless you're sure you want a global change. Use the localParams() instead after setting a navigation target.
  • Assume a NPC is a player-type. Mob types have some important differences.

Download an example

This is a link to a an example trait. It is similar to the code above, with some additional code for better handling commands, default configuration, and a plugin.yml

You will need to build against CitizensAPI.jar,Citizens.jar (although this is not always required), and Bukkit.jar.

NPC Events

Citizens implements its own Listeners and will call new NPC-specific versions of many common events. This saves Trait developers the trouble of finding their npcs from the normal event entities. The event object these events provide are just like their Bukkit counterparts with the addition of the getNPC() method. Citizens currently provides the following:

  • EntityTargetNPCEvent
  • NPCChatEvent
  • NPCClickEvent
  • NPCCollisionEvent
  • NPCCombustByBlockEvent
  • NPCCombustByEntityEvent
  • NPCCombustEvent
  • NPCDamageByBlockEvent
  • NPCDamageByEntityEvent
  • NPCDamageEvent
  • NPCDeathEvent
  • NPCDespawnEvent
  • NPCEvent
  • NPCLeftClickEvent
  • NPCPushEvent
  • NPCRemoveEvent
  • NPCRightClickEvent
  • NPCSelectEvent
  • NPCSpawnEvent
  • PlayerCreateNPCEvent

See the [Javadocs] for details.

Using the AI API

The AI API of Citizens can be broken down into two parts - GoalController and Navigator.

A Goal is a repeatable, abstract unit of work that can be performed by an NPC. It can be registered with a GoalController with a priority (higher is more important). The highest priority goal which can be executed will be prioritised. NPC contains getDefaultGoalController() for this purpose.

The GoalSelector allows a great deal of flexibility within goal implementations. It allows firstly the dynamic selection of sub-goals and the concurrent execution of many sub-goals, and can stop execution at any time.

In recent versions of CitizensAPI the "Behavior" class is introduced which allows a behavior tree-based AI approach that is backwards compatible with Goals and GoalControllers.


Code: Example
{{{2}}}

The second concept is the Navigator. This controls the pathfinding aspects of the NPC. The Navigator can have one target at a time, and will call events to notify of completion/cancellation:

  • NavigationBeginEvent
  • NavigationCancelEvent
  • NavigationCompleteEvent
  • NavigationEvent
  • NavigationReplaceEvent

The pathfinding range of the Navigator is the maximum range it will search when attempting to find a path to the target. This is usually set by the server admin. The speed modifier of the Navigator is the % modified movement speed of the NPC while moving to the target.

Using the Persistence API

Sometimes, traits can store a lot of simple variables such as primitives, Strings, Locations, and others. Saving/loading them via the trait API can be a little bit of overkill.

Citizens 2.0.4+ provides a simple Persistence API to automatically save and load these variables using DataKeys. The key to this API is the @Persist annotation. Sample code is provided below.

Code: Example
{{{2}}}

More advanced use of the API can be found in the @DelegatePersistence annotation. This allows complex types such as Locations to be saved and loaded with finer grained control. These types can be given default delegates by calling PersistenceLoader#registerPersistDelegate(Persister) - Location has a built in Persister for convenience.


Code: Example
{{{2}}}

See Also

Characters