Skip to content
iPlugin

注册事件条目

本文介绍了如何注册并处理与任务目标相关的事件

描述

开发者可以通过自定义 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)