Race Reference

From Citizens Wiki

Creating a Race

Race folders need to go in [server folder]/plugins/Adventures/races/YourRaceHere. Every race needs a descriptor, or a file that tells Adventures what to load for your race. This will be info.yml OR info.js OR info.extension, where extension is an embedded Java script language such as Jython or JRuby.

If a scripting language is used for the info file, it will need to have a getDescriptor() method in the root namespace which returns an instance of net.citizensnpcs.adventures.race.RaceDescriptor.

YAML Info File Structure

Example YAML file showing all currently available keys:

name: Name # required
tribe:
     max-size: 10 # required
     behavior: # optional, a behavior root node (explained later)
members:
     names: # required, a list of possible names for new members to have, picked at random
         0: Bob
         1: SirBob
         2: Bob2
     types: # required, a list of possible entity types for new members to have, picked at random
         0: CREEPER
     behavior: # optional, a behavior root node (explained later)
dialog:
     allowed-rules: rule1, filename1 # comma-separated list of rules to allow (can be per-rule or per-file). Leave empty for all rules allowed.

The behavior root nodes are important for tribes. They are defined as a decision tree of behaviors, which are a single unit of work for an NPC. A tree is a way of organising data which looks similar to an upside-down tree. For a simple illustration, look here. The NPC's AI will start from the top and work its way down to a behavior.

There are three flow constructs that help with behavior flows: sequences, selectors, and decorators. A sequence simply executes each behavior in a list one-by-one until they are all finished. A selector picks one or more behaviors from a list based on some kind of strategy, like a random selection or a priority-based selection. A decorator wraps another behavior without knowing what it does, for things like stopping it after a certain amount of time, or inverting its responses, or doing something before/after it completes.

Finally we have the edge nodes, which are user-defined and do actual work with the NPC. This is a very powerful construct that allows complex behaviors to emerge.

We define this in YAML like so:

behavior:
    sequence: # builds a sequence
        sub: # omitted
    sequence -r: # builds a sequence which retries children if they fail until the sequence is complete
    selector: # builds a random selector
        sub: # omitted
        sub2: # omitted
    selector -r: # retries children if they fail until a successful behavior completes
    selector -p: # prioritises children
    js filename: "" # loads a javascript goal at the file location under your race folder and invokes the getBehavior(Tribe, DataKey) function on it to get a Behavior instance.
    your.package.name.ClassName: # loads the class at the given package and instantiates it to get a Behavior instance. Must have a 0-argument constructor (note that @Persist annotations from CitizensAPI will work for loading extra data).