注册事件条目
本文介绍了如何注册并处理与任务目标相关的事件
描述
开发者可以通过自定义 Objective 类来监听特定事件,并为任务目标添加条件节点(Node)。
每个 Objective 代表一个任务目标,通常会监听 Minecraft 中的某个事件(如方块破坏、玩家互动等)。
通过实现 checkNode 方法,开发者能够为事件创建具体的条件检查,确保目标在任务中的进度能够正确判断。
定义 Objective 类并实现
要创建自定义的目标类,开发者需要继承 Objective 类,并实现事件类型 event、名称 name 和 getPlayer() 方法。
event:表示目标监听的 Minecraft 事件类型,例如方块破坏事件BlockBreakEvent。name:表示该目标的唯一名称,用于在配置文件中标识。getPlayer():用于从事件中获取触发该事件的玩家。
在 checkNode 中添加条件判断
在 checkNode 方法中,您可以根据事件数据(例如 BlockBreakEvent)添加条件节点。每个节点根据条件执行相应的验证,如检查破坏的方块类型、物品的数量等。
使用 nodeDefault(推荐方式)
在 checkNode 方法中,通常使用 nodeDefault 来检查条件并返回进度数量(Int)。以下是一个方块破坏目标的示例:
@ObjectiveRegister
class BlockBreakObjective : Objective<BlockBreakEvent>() {
override val event = BlockBreakEvent::class.java
override val name = "block break"
// 获取玩家
override fun getPlayer(event: BlockBreakEvent): Player {
return event.player
}
// 添加目标节点并检查条件
override fun checkNode(objectiveDTO: ObjectiveDTO, event: BlockBreakEvent): Int {
val block = event.block
val blockType = block.type.name
val player = event.player
return objectiveDTO.nodeDefault {
withConditions(
nodeCondition<List<String>>("material") { it.contains(blockType) }, // 方块类型
positionNode(block), // 方块位置
nodeCondition<Int>("exp") { it <= event.expToDrop }, // 经验
nodeCondition<Boolean>("silk-touch") { // 精准采集
if (player.inventory.itemInMainHand.itemMeta?.hasEnchant(Enchantment.SILK_TOUCH) == true) {
it
} else true
}
)
}
}
}使用 withNode(外部项目使用)
如果您需要在外部项目中使用这些条件检查函数,可以使用 withNode DSL。withNode 返回 Boolean 值,表示条件是否满足:
val result = objectiveDTO.withNode {
withConditions(
positionNode(player.location),
nodeCondition<String>("key") { it == "value" }
)
}注意:withNode 主要用于外部项目独立使用条件检查,在 checkNode 方法中通常使用 nodeDefault。
对应任务配置文件
在任务的配置文件中,您可以为目标指定条件。任务的配置文件定义了事件条目监听的事件及其节点条件,如下所示:
示例:方块破坏目标配置
objective:
1:
event: block break
node:
material:
- STONE
amount: 2条件判断与节点匹配
在 checkNode 方法中,您可以通过 nodeCondition 来检查事件数据与配置文件中定义的条件是否匹配。
nodeCondition 是一个泛型函数,第一个参数是配置文件中节点的键名,第二个参数是一个条件判断 lambda。如果配置文件中没有该节点,则默认返回 true。
例如,检查破坏的方块类型是否为 STONE,并且破坏的方块数量是否达到指定数量。
节点条件和条件逻辑
您可以使用 withConditions 方法将多个条件组合在一起。该方法接收多个布尔值条件,当所有条件都为 true 时返回 true。例如,您可以检查方块类型、玩家是否持有某种物品、玩家是否在特定位置等。
在 nodeDefault lambda 中(ObjectiveConfig 上下文):
objectiveDTO.nodeDefault {
withConditions(
nodeCondition<List<String>>("material") { it.contains(blockType) }, // 检查方块类型
positionNode(block), // 检查方块位置
nodeCondition<Int>("exp") { it <= event.expToDrop }, // 检查经验
nodeCondition<Boolean>("silk-touch") { // 检查是否有精准采集
player.inventory.itemInMainHand.itemMeta?.hasEnchant(Enchantment.SILK_TOUCH) == true
}
)
}在 withNode lambda 中(Map<String, Any> 上下文):
objectiveDTO.withNode {
withConditions(
positionNode(player.location),
nodeCondition<String>("key") { it == "value" }
)
}内置 NodeCondition 方法
为了简化条件判断,API 提供了多个内置的方法,您可以直接使用它们来进行常见的条件判断。这些方法同时支持 ObjectiveConfig 扩展函数(在 nodeDefault lambda 中使用)和 Map<String, Any> 扩展函数(在 withNode lambda 中使用)。
以下是 NodeCondition 对象的常用方法:
-
positionNode:检查位置或实体是否符合条件。- 支持
Location、Entity和Block类型。
fun ObjectiveConfig.positionNode(location: Location?): Boolean fun ObjectiveConfig.positionNode(entity: Entity?): Boolean fun ObjectiveConfig.positionNode(block: Block?): Boolean // Map 扩展版本 fun Map<String, Any>.positionNode(location: Location?): Boolean fun Map<String, Any>.positionNode(entity: Entity?): Boolean fun Map<String, Any>.positionNode(block: Block?): Boolean - 支持
-
materialNode:检查物品类型是否符合条件。- 支持单个物品或物品列表。
fun ObjectiveConfig.materialNode(item: ItemStack?, key: String = "material"): Boolean fun ObjectiveConfig.materialNode(items: List<ItemStack>): Boolean // Map 扩展版本 fun Map<String, Any>.materialNode(item: ItemStack?, key: String = "material"): Boolean fun Map<String, Any>.materialNode(items: List<ItemStack>): Boolean -
blockNode:检查方块类型是否符合条件。fun ObjectiveConfig.blockNode(block: Block?, key: String = "material"): Boolean fun Map<String, Any>.blockNode(block: Block?, key: String = "material"): Boolean -
entityNode:检查实体是否符合条件。fun ObjectiveConfig.entityNode(entity: Entity): Boolean fun Map<String, Any>.entityNode(entity: Entity): Boolean -
worldNode:检查玩家所在世界是否符合条件。fun ObjectiveConfig.worldNode(player: Player): Boolean fun Map<String, Any>.worldNode(player: Player): Boolean
使用 NodeCondition 方法
在使用这些方法时,您需要导入相应的扩展函数:
import com.hiusers.questengine.api.quest.NodeCondition.positionNode
import com.hiusers.questengine.api.quest.NodeCondition.entityNode
import com.hiusers.questengine.api.quest.NodeCondition.materialNode然后在 nodeDefault lambda 中直接调用:
objectiveDTO.nodeDefault {
withConditions(
positionNode(entity),
entityNode(entity),
materialNode(player.equipment?.itemInMainHand, "item")
)
}或者在 withNode lambda 中调用:
objectiveDTO.withNode {
withConditions(
positionNode(player.location),
nodeCondition<String>("key") { it == "value" }
)
}自动注册事件条目类
为了简化事件目标的注册,API 提供了 @ObjectiveRegister 注解。开发者只需在事件条目类的头部添加该注解。
@ObjectiveRegister
class CustomObjective : Objective<CustomEvent>() {要求前置依赖
如果您的 Objective 依赖于其他插件,可以在注解中指定插件名称:
@ObjectiveRegister("插件依赖名称")@ObjectiveRegister("Citizens")
class CitizensRightObjective : Objective<NPCRightClickEvent>() {
}小结
通过继承 Objective 类,开发者可以创建特定的事件条目,并通过 checkNode 方法定义任务条件。
每个事件条目会监听特定的 Minecraft 事件,并根据配置文件中定义的节点条件来进行判断。
开发者不需要直接处理任务进度的更新,只需要添加相应的条件节点即可。API 会自动处理进度更新和任务完成逻辑。
- 在
checkNode方法中,使用nodeDefault返回进度数量(Int) - 在外部项目中,可以使用
withNode进行独立的条件检查(返回 Boolean)