• 欢迎来到Minecraft插件百科!
  • 对百科编辑一脸懵逼?帮助:快速入门带您快速熟悉百科编辑!
  • 因近日遭受攻击,百科现已限制编辑,有意编辑请加入插件百科企鹅群:223812289

Citizens/API

来自Minecraft插件百科
Qsefthuopq留言 | 贡献2018年11月25日 (日) 07:39的版本 →‎NPC Events
跳转到导航 跳转到搜索

最新正式版下载地址: Jenkins

开发版下载地址: Jenkins

文档: JavaDocs

源码: Github

快捷导航
用法 安装  · 常见疑问  · 指令  · 编辑器  · 兼容性  · API
配置 数据存储  · 权限  · 限制  · 经济  · 翻译
角色 Denizen  · 哨兵  · 冒险家  · 炼金术士  · 铁匠  · DtlTraders  · 任务  · 建筑者  · 快递员  · HyperMerchant
工具 / 信息 下载  · 1.2 版本文件转换器  · IRC聊天室

Citizens拥有广泛的API来让你制作与npc相关的插件或给npc添加新的角色特性。 确认你使用的是最新版的CitizensAPI来兼容最新版的Citizens.

你可以在这里找到Javadocs:http://jd.citizensnpcs.co

如果你在使用 API的过程中遇到了问题 请在github 进行反馈 https://github.com/CitizensDev/Citizens2/issues 或者在Discord反馈:https://discord.gg/Q6pZGSR


正确链接Java

Citizens和大多数的Java项目一样是用的Maven构造而成的。你构造关联citizens的插件也应该用Maven。

在你的 pom.xml (Maven 项目)文件内, 你可以使用这个 repository:

    <repository>
        <id>everything</id>
        <url>http://repo.citizensnpcs.co/</url>
    </repository>

和这个:

    <dependency>
        <groupId>net.citizensnpcs</groupId>
        <artifactId>citizens</artifactId>
        <version>VERSION</version>
        <type>jar</type>
        <scope>provided</scope>
    </dependency>

并把 VERSION改为当前版本的Citizens (可以在 http://ci.citizensnpcs.co/job/Citizens2/ 看到Citizens版本号 ID), 比如 2.0.23-SNAPSHOT (but with the version numbers changed to the relevant version).

在大多数情况下,最好链接 citizens 而不是 API 项目, 因为很多有用的 classes 和 utilities不在API内. Citizens的项目 包括 API和添加的更多选项.

关联Citizens

关联Citizens和创建一个普通的插件一样简单,只需添加 depend: [Citizens] 到你的 plugin.yml 内即可. From here, a common basic entry point is the CitizensAPI class. 这给予你 NPCRegistry for NPC lookup, as well as the TraitFactory which allows trait registration. If Citizens is not loaded, all CitizensAPI.* methods will return null.

创建一个 NPC

创建npc最简单的方法就是使用 NPCRegistry 这个东西来管理npc的存储和创建 . 默认的registry由CitizensAPI.getNPCRegistry() 给予, 并且你可以用不同的存储方式来创建一个新的NPC. 一个玩家类型的名为"fullwall"的NPC可以这一创建:

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

检测实体是否是NPC

Citizens的 NPC拥有设置为true的 "NPC"元数据. 示例:

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

创建特性

特征是链接到NPC并提供特定功能的持久、可附加的板块。 这可以是任何东西,可以是带有动态AI会进行简单谈话的村民特性.

如果使用Maven, Citizens的Maven repo 可以在 http://repo.citizensnpcs.co 找到

想要注册一个特性,你可以使用 TraitFactory class. 这个东西可以控制特性的注册.

Code: 注册示例和简易特性
//这个特性可以应用于NPC,输入 /trait [我的特性名] 即可应用. 每个NPC gets its own instance of this class.
//这个特性class has a reference to the attached NPC class through the protected field 'npc' or getNPC().
//这个特性class也实现了监听器的功能所以你可以直接把EventHandlers添加到你的特性插件里 .
@TraitName("mytraitname") // 最好取简单点的名字来方便注释
public class MyTrait extends Trait {
	public MyTrait() {
		super("我的特性名");
		plugin = JavaPlugin.getPlugin(MyPlugin.class);
	}

	MyPlugin plugin = null;

	boolean SomeSetting = false;
        
        // 查看'Persistence API' 部分
        @Persist("mysettingname") boolean automaticallyPersistedSetting = false;

	// 你可以在这里加载你之前保存的数值 (可选). 
        // 在第一次应用特性时不会使用这个, 只会在已服务器存在的NPC上加载.
        // 这叫做 AFTER onAttach so you can load defaults in onAttach and they will be overridden here.
        // This is called BEFORE onSpawn, npc.getBukkitEntity() will return null.
	public void load(DataKey key) {
		SomeSetting = key.getBoolean("SomeSetting", false);
	}

	// Save settings for this NPC (optional). These values will be persisted to the Citizens saves file
	public void save(DataKey key) {
		key.setBoolean("SomeSetting",SomeSetting);
	}

        // An example event handler. All traits will be registered automatically as Bukkit Listeners.
	@EventHandler
	public void click(net.citizensnpcs.api.event.NPCClickEvent event){
		//Handle a click on a NPC. The event has a getNPC() method. 
		//Be sure to check event.getNPC() == this.getNPC() so you only handle clicks on this NPC!
		
	}
      
        // Called every tick
        @Override
        public void run() {
        }

	//Run code when your trait is attached to a NPC. 
        //This is called BEFORE onSpawn, so npc.getBukkitEntity() will return null
        //This would be a good place to load configurable defaults for new NPCs.
	@Override
	public void onAttach() {
		plugin.getServer().getLogger().info(npc.getName() + "has been assigned MyTrait!");
	}

        // Run code when the NPC is despawned. This is called before the entity actually despawns so npc.getBukkitEntity() is still valid.
	@Override
	public void onDespawn() {
        }

	//Run code when the NPC is spawned. Note that npc.getBukkitEntity() will be null until this method is called.
        //This is called AFTER onAttach and AFTER Load when the server is started.
	@Override
	public void onSpawn() {

	}

        //run code when the NPC is removed. Use this to tear down any repeating tasks.
	@Override
	public void onRemove() {
        }

}

//This is your bukkit plugin class. Use it to hook your trait into Citizens and handle any commands.
public class MyPlugin extends org.bukkit.plugin.java.JavaPlugin {

	public void onEnable() {
	
	//check if Citizens is present and enabled.

		if(getServer().getPluginManager().getPlugin("Citizens") == null || getServer().getPluginManager().getPlugin("Citizens").isEnabled() == false) {
			getLogger().log(Level.SEVERE, "Citizens 2.0 not found or not enabled");
			getServer().getPluginManager().disablePlugin(this);	
			return;
		}	

		//Register your trait with Citizens.        
		net.citizensnpcs.api.CitizensAPI.getTraitFactory().registerTrait(net.citizensnpcs.api.trait.TraitInfo.create(MyTrait.class));	
	}

	@Override
	public boolean onCommand(CommandSender sender, Command cmd, String cmdLabel, String[] inargs) {
		//handle commands for /myplugin 
	}
}

使用须知

DO

  • 在使用 npc.getBukkitEntity() 之前检查 npc.isSpawned()
  • 在使用 npc.getNavigator() 之前检查 npc.isSpawned()
  • 如果希望这个特性运行多个实例,请创建单独的单例监听器class.这可以让 called 事件更高效.
  • Honor npc.data().get(NPC.DEFAULT_PROTECTED_METADATA) 如果这个为true,NPC 会变得'无敌',无法受到普通攻击的伤害 .
  • 用 CitizensAPI.getNPCRegistry().isNPC() 来检查实体是否为NPC. 真正的玩家和玩家类型的NPC都会return true for instanceof Player.

DON'T

  • 不要尝试从特性内获取 npc.getBukkitEntity() ,直到onSpawn() 被 called 或 npc.isSpawned() returns true.
  • 不要改变npc.getNavigator.getDefaultParams() 里的任何东西,除非你想要彻底改变插件.使用 localParams() 而不是 after 来设置导航目标.
  • 不要假设NPC的类型为玩家.怪物类型有很大的区别.

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事件

Citizens 执行自己的监听器并call new NPC-specific versions of many common events. 这避免了特性开发者从正常事件实体中查找npc的麻烦. The event object these events provide are just like their Bukkit counterparts with the addition of the getNPC() method. Citizens提供以下事件:

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

详情查看 [Javadocs]

使用 AI API

AI API 可分为两部分: - 目标控制器导航器.

一个目标 可以重复, 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.

目标选择器可以使目标更加灵活.首先它可以动态选择子目标并同时执行多个目标,并且可以随时停止.

最近的CitizensAPI版本里, "Behavior" class is introduced which allows a behavior tree-based AI approach that is backwards compatible with Goals and GoalControllers.


Code: Example
 public class MyGoal implements Goal {
     private Object state;
     private GoalSelector selector; // 当前选择器
     public void reset() {
         state = null;
         // 这种方式可以被多次called - tear down any state
     }
     public void run() {
         if(!npcIsCool()) {
             selector.finish(); // stops execution
         } else if (npcIsAwesome()){
             selector.select(new AwesomeGoal()); // this switches execution to AwesomeGoal and stops execution of this goal.
         } else if (npcNeedsCool()) {
             selector.selectAdditional(new AccumulateCoolGoal()); // AccumulateCoolGoal executes concurrently to this goal.
         }
     }
     public boolean shouldExecute(GoalSelector selector) {
         if (npcIsCool()) {
             this.selector = selector;
             return true;
         }
         return false;
     }
 }

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.

使用永久API

有时候, 特性可以存储大量的变量,比如primitives, Strings, 地点和其他.通过特性的API保存/加载这些东西可能有点困难.

Citizens 2.0.4+提供了简易的永久API使用DataKeys来自动保存和加载这些变量.这个API的key是 @Persist annotation. 示例代码如下.

Code: Example
 public class MyTrait extends Trait {
     // logic omitted.

    @Persist boolean myVariable = false; // the default value of @Persist saves the value under the field name (in this case, 'myVariable').
    
    @Persist("newkey") int intVariable = 11; // this saves the value under 'newkey'. The default value of the variable has been set to 11 - this will be used when loading if the key doesn't exist.

    @Persist(value="newkey", required=true) String required; // if the value under 'newkey' doesn't exist, then the trait will fail to load.
 }

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
 public class MyTrait extends Trait {
     // logic omitted.

    @Persist 
    @DelegatePersistence(ExplicitComplexTypePersister.class) // explicit delegation
    ComplexType myComplexType;

    @Persist ComplexType implicitComplexType; // implicit delegation
    static {
        PersistenceLoader.registerPersistDelegate(ImplicitComplexTypePersister.class);
    }
 }
 
 public class ExplicitComplexTypePersister implements Persister {
     public Object create(DataKey root) {
         return new ComplexType(root.getInteger("complexstructures"));
     }
     public void save(Object instance, DataKey root) {
         ComplexType real = (ComplexType) instance; // guaranteed cast - will always succeed.
         root.setInteger("complexstructures", real.getComplexStructure());
     }
 }

查看

Characters