- 欢迎来到Minecraft插件百科!
- 对百科编辑一脸懵逼?帮助:快速入门带您快速熟悉百科编辑!
- 因近日遭受攻击,百科现已限制编辑,有意编辑请加入插件百科企鹅群:223812289
Citizens/API:修订间差异
Qsefthuopq(留言 | 贡献) |
Qsefthuopq(留言 | 贡献) |
||
第183行: | 第183行: | ||
* 不要假设NPC的类型为玩家.怪物类型有很大的区别. | * 不要假设NPC的类型为玩家.怪物类型有很大的区别. | ||
=== | ===下载一个示例=== | ||
通过这个链接你可以下载到一个插件示例. 和上面的代码一样, 但这会有一些更好的代码来处理指令、默认配置和plugin.yml. | |||
*[https://github.com/jrbudda/Citizens2/downloads | *[https://github.com/jrbudda/Citizens2/downloads 点击下载] | ||
你需要基于 [http://ci.citizensnpcs.co/job/CitizensAPI/ CitizensAPI.jar]、[http://ci.citizensnpcs.co/job/Citizens2/ Citizens.jar]和[http://dl.bukkit.org/downloads/bukkit/ Bukkit.jar].来构造插件 | |||
==NPC事件== | ==NPC事件== |
2018年11月25日 (日) 07:42的最新版本
快捷导航 | |
---|---|
用法 | 安装 · 常见疑问 · 指令 · 编辑器 · 兼容性 · 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的类型为玩家.怪物类型有很大的区别.
下载一个示例
通过这个链接你可以下载到一个插件示例. 和上面的代码一样, 但这会有一些更好的代码来处理指令、默认配置和plugin.yml.
你需要基于 CitizensAPI.jar、Citizens.jar和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());
}
}
|