📡 事件:QISkillUseEvent
QS 的技能释放主链路是一个 Bukkit 事件 —— QISkillUseEvent。它由 QinhCoreLib 提供(不是 QS 也不是 QI),三方共用同一 EventBus 契约。本章讲它的字段、QS 自己怎么用它、以及别的插件如何监听 / 取消 / 读结果。本文档对应 QS 1.0.22。
1. 事件身份
包名:com.qinhuai.corelib.action.skill
类名:QISkillUseEvent (extends PlayerEvent, implements Cancellable)为什么放在 CoreLib?因为 QI 负责"按下"、QS 负责"能不能放",两边都要引用同一个事件类型。把它放进双方都硬依赖的 CoreLib,才能共享同一条事件总线契约。
每一次技能释放(物品按键、命令、QinhSkillsAPI 调用、被动触发)都会经 SkillEventGateway.dispatch 发出一个该事件。
2. 字段一览
| 字段 | 类型 | 读/写 | 含义 |
|---|---|---|---|
player | Player | 读 | 释放者(PlayerEvent.getPlayer()) |
payload | String | 读 | 原始 payload(技能 id / JSON) |
trigger | String | 读 | 兼容字符串触发标签(如 "api"、QI action 键) |
triggerType | TriggerType | 读 | 归一后的触发枚举(fromLegacy(trigger)) |
item | ItemStack? | 读 | 触发用的物品(命令/API 触发时为 null) |
itemId | String? | 读 | 触发物品的 id |
rawContext | RawSkillContext? | 读 | 原始上下文(可空),承载 itemId / item / 潜行 / 来源等触发现场信息,由 QinhCoreLib 提供 |
skillHandled | Boolean | 读/写 | QS 是否已处理(成功释放时置 true) |
castResult | String? | 读/写 | CastResult.name(如 "SUCCESS"、"ON_COOLDOWN") |
castAttempted | Boolean | 读/写 | 是否进入过门控/执行尝试 |
fallbackInvoked | Boolean | 读/写 | 是否走了 fallback 处理器 |
mythicInvoked | Boolean | 读/写 | 是否调到了 MythicMobs 执行 |
primaryPipeline | Boolean | 读/写 | 是否主链路(默认 true) |
取消相关:isCancelled() / setCancelled(Boolean)(来自 Cancellable)。
⚠️
castResult是字符串,不是枚举。它是CastResult的.name。要拿枚举请CastResult.valueOf(it)(注意未来新增结果码时做容错)。
3. QS 自己怎么用它
QS 内部有两条相关角色:
a) 网关发事件 —— SkillEventGateway
SkillEventGateway.dispatch 构造事件并 callEvent,随后根据结果回收 CastResult:
val event = QISkillUseEvent(
player = player,
payload = payload,
trigger = trigger,
triggerType = TriggerType.fromLegacy(trigger),
)
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) return CastResult.SCRIPT_BLOCKED
if (!event.skillHandled) return event.castResult?.let { CastResult.valueOf(it) } ?: CastResult.MYTHIC_FAILED
return event.castResult?.let { CastResult.valueOf(it) } ?: CastResult.SUCCESSb) 监听并执行 —— QS 的核心监听器
QS 监听 QISkillUseEvent,跑完整运行时(归一 → 状态机 → 图解析 → 门控 → 执行 → 后处理),然后回填 skillHandled / castResult / mythicInvoked 等字段。
c) QI 动作系统对接 —— QiListener
QS 还实现了 CoreLib 的 QinhActionHandler 契约(QiListener),用 handlerId = "qinhskills:cast" 注册进 QI 的动作系统。这条是 fallback 路径(主链路是 QI 直接 dispatchViaEvent 发事件),它不合成第二个事件,只在主链未处理时兜底。
class QiListener : QinhActionHandler {
override val handlerId: String = QISkillBridge.HANDLER_ID // "qinhskills:cast"
override fun isAvailable(): Boolean = true
override fun dispatch(context: QinhActionContext): ActionDispatchResult { /* 兜底执行 */ }
}4. 别的插件如何监听
任意插件都可注册标准 Bukkit 监听器。常见用途:审计、封禁某些技能、对释放打 buff/记录。
读结果(监听后,优先级靠后)
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
fun onSkill(event: QISkillUseEvent) {
val skillId = QinhSkillsAPI.resolvePayloadSkillId(event.payload) ?: return
if (event.skillHandled && event.castResult == "SUCCESS") {
plugin.logger.info("${event.player.name} 成功释放 $skillId(mythic=${event.mythicInvoked})")
}
}取消(拦截某技能)
@EventHandler(priority = EventPriority.HIGH)
fun blockInArena(event: QISkillUseEvent) {
val skillId = QinhSkillsAPI.resolvePayloadSkillId(event.payload) ?: return
if (skillId == "dash" && inSafeZone(event.player)) {
event.isCancelled = true // QS 收到取消 → 回 SCRIPT_BLOCKED,技能不放
}
}取消事件会让
SkillEventGateway返回CastResult.SCRIPT_BLOCKED,技能不会释放、不扣资源、不进冷却。
5. 监听优先级建议
| 你想做的事 | 建议优先级 | 说明 |
|---|---|---|
| 拦截 / 阻止某些技能 | HIGH / HIGHEST | 在 QS 处理前取消 |
| 只读结果做记录 | MONITOR + ignoreCancelled = true | QS 已回填 castResult |
| 改 payload 前置数据 | LOWEST | 极少需要;注意别破坏归一 |
QS 的核心监听处于中段优先级并回填字段。把你的"只读"逻辑放
MONITOR才能读到 QS 的最终判定结果。
6. payload 怎么解析
事件里的 payload 可能是纯技能 id,也可能是物品插件透传的 JSON。别自己手撕,交给 API:
val skillId: String? = QinhSkillsAPI.resolvePayloadSkillId(event.payload)返回值统一小写,解析不出返回 null。