pluginiPlugin

事件监听开发

监听和处理 Zaphkiel 物品事件

概述

Zaphkiel 提供了丰富的事件系统,允许开发者监听物品的各种状态变化和交互行为。通过监听这些事件,你可以在物品构建、释放、交互等关键时刻执行自定义逻辑。

事件系统架构

事件监听机制

Zaphkiel 的事件系统通过 ItemListener 监听 Bukkit 事件并转换为 Zaphkiel 特定的事件:

@SubscribeEvent
fun onInteract(e: PlayerInteractEvent) {
    if (e.item.isAir()) {
        return
    }
    val itemStream = e.item!!.toItemStream()
    if (itemStream.isVanilla()) {
        return
    }
    // 触发事件
    val event = ItemEvent.Interact(itemStream, e)
    if (event.call()) {
        if (event.save) {
            event.itemStream.rebuildToItemStack(e.player)
        }
        // 执行脚本
        when (e.action) {
            Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK -> {
                itemStream.getZaphkielItem().invokeScript(listOf("on_left_click", "onLeftClick"), e, itemStream)
            }
            Action.RIGHT_CLICK_AIR, Action.RIGHT_CLICK_BLOCK -> {
                itemStream.getZaphkielItem().invokeScript(listOf("on_right_click", "onRightClick"), e, itemStream)
            }
        }
    }
}

核心事件类型

物品构建事件

物品构建过程中的事件:

// 监听构建前事件
@EventHandler
fun onItemBuildPre(event: ItemBuildEvent.Pre) {
    val item = event.item
    val player = event.player
    val itemStream = event.itemStream
    
    // 可以修改名称和描述
    if (item.id == "special_weapon") {
        event.addName("custom_suffix", " [特殊]")
        event.addLore("warning", "&c注意:这是特殊武器")
    }
    
    // 可以取消构建
    if (player != null && !player.hasPermission("zaphkiel.special")) {
        event.isCancelled = true
    }
}
 
// 监听构建后事件
@EventHandler
fun onItemBuildPost(event: ItemBuildEvent.Post) {
    val item = event.item
    val itemStream = event.itemStream
    
    // 构建完成后的处理
    if (item.id.startsWith("magic_")) {
        // 添加魔法物品标记
        itemStream.getZaphkielData().putDeep("magic_item", true)
    }
}

物品释放事件

物品从 ItemStream 转换为 ItemStack 时的事件:

// 监听物品释放事件
@EventHandler
fun onItemRelease(event: ItemReleaseEvent) {
    val itemStream = event.itemStream
    val item = event.item
    
    // 修改物品材质
    if (item.id == "rainbow_sword") {
        val colors = listOf(Material.RED_WOOL, Material.BLUE_WOOL, Material.GREEN_WOOL)
        event.icon = colors.random()
    }
    
    // 修改物品 Meta
    val lore = event.itemMeta.lore?.toMutableList() ?: mutableListOf()
    lore.add("&7释放时间: ${System.currentTimeMillis()}")
    event.itemMeta.lore = lore
}
 
// 监听显示选择事件
@EventHandler
fun onDisplaySelect(event: ItemReleaseEvent.SelectDisplay) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 根据玩家等级选择不同显示模板
    if (player != null && player.level >= 50) {
        val advancedDisplay = Zaphkiel.api().getItemManager().getDisplay("advanced_display")
        if (advancedDisplay != null) {
            event.display = advancedDisplay
        }
    }
}
 
// 监听显示生成事件
@EventHandler
fun onDisplayGenerate(event: ItemReleaseEvent.Display) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 动态修改显示内容
    if (player != null) {
        event.addName("player_name", player.name)
        event.addLore("player_level", "玩家等级: ${player.level}")
    }
}

物品交互事件

玩家与物品交互时的事件:

// 监听物品交互事件
@EventHandler
fun onItemInteract(event: ItemEvent.Interact) {
    val itemStream = event.itemStream
    val bukkitEvent = event.bukkitEvent
    val player = bukkitEvent.player
    
    // 检查特定物品
    if (itemStream.getZaphkielItem().id == "teleport_wand") {
        // 处理传送逻辑
        val data = itemStream.getZaphkielData()
        val cooldown = data.getDeep("cooldown")?.asLong() ?: 0L
        
        if (System.currentTimeMillis() - cooldown > 5000) {
            // 执行传送
            player.teleport(player.world.spawnLocation)
            data.putDeep("cooldown", System.currentTimeMillis())
            event.save = true  // 标记需要保存
        } else {
            player.sendMessage("&c传送冷却中...")
            bukkitEvent.isCancelled = true
        }
    }
}
 
// 监听物品消耗事件
@EventHandler
fun onItemConsume(event: ItemEvent.Consume) {
    val itemStream = event.itemStream
    val bukkitEvent = event.bukkitEvent
    val player = bukkitEvent.player
    
    // 自定义消耗逻辑
    if (itemStream.getZaphkielItem().id == "magic_potion") {
        // 给予特殊效果
        player.addPotionEffect(PotionEffect(PotionEffectType.SPEED, 600, 1))
        player.sendMessage("&a你感到身体变得轻盈!")
    }
}

高级事件监听

异步事件处理

// 监听异步 Tick 事件
@EventHandler
fun onAsyncTick(event: ItemEvent.AsyncTick) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 异步处理逻辑(不要修改 Bukkit 对象)
    val item = itemStream.getZaphkielItem()
    if (item.id == "energy_crystal") {
        val data = itemStream.getZaphkielData()
        val energy = data.getDeep("energy")?.asInt() ?: 0
        
        // 每 5 秒恢复 1 点能量
        if (energy < 100) {
            data.putDeep("energy", energy + 1)
            event.save = true
        }
    }
}

背包点击事件

// 监听背包点击事件
@EventHandler
fun onInventoryClick(event: ItemEvent.InventoryClick) {
    val currentStream = event.itemStreamCurrent
    val buttonStream = event.itemStreamButton
    val bukkitEvent = event.bukkitEvent
    
    // 处理特殊物品的点击
    if (currentStream != null && currentStream.getZaphkielItem().id == "locked_item") {
        // 阻止移动锁定物品
        bukkitEvent.isCancelled = true
        bukkitEvent.whoClicked.sendMessage("&c这个物品已被锁定!")
    }
    
    // 处理组合逻辑
    if (currentStream != null && buttonStream != null) {
        val currentId = currentStream.getZaphkielItem().id
        val buttonId = buttonStream.getZaphkielItem().id
        
        if (currentId == "upgrade_stone" && buttonId == "basic_sword") {
            // 执行升级逻辑
            handleItemUpgrade(bukkitEvent.whoClicked as Player, currentStream, buttonStream)
            event.saveCurrent = true
            event.saveButton = true
        }
    }
}

事件优先级和取消

设置事件优先级

// 高优先级监听器(最先执行)
@EventHandler(priority = EventPriority.HIGHEST)
fun onItemBuildHighest(event: ItemBuildEvent.Pre) {
    // 最高优先级的处理逻辑
}
 
// 低优先级监听器(最后执行)
@EventHandler(priority = EventPriority.LOWEST)
fun onItemBuildLowest(event: ItemBuildEvent.Pre) {
    // 最低优先级的处理逻辑
}

事件取消处理

@EventHandler
fun onItemBuild(event: ItemBuildEvent.Pre) {
    val item = event.item
    val player = event.player
    
    // 条件检查
    if (player != null && !player.hasPermission("zaphkiel.use." + item.id)) {
        event.isCancelled = true
        player.sendMessage("&c你没有权限使用这个物品!")
        return
    }
    
    // 其他逻辑...
}

事件数据操作

修改物品数据

@EventHandler
fun onItemBuild(event: ItemBuildEvent.Pre) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 根据玩家属性调整物品数据
    if (player != null) {
        val data = itemStream.getZaphkielData()
        val baseDamage = data.getDeep("damage")?.asInt() ?: 10
        
        // 根据玩家等级增加伤害
        val levelBonus = player.level * 2
        data.putDeep("damage", baseDamage + levelBonus)
        
        // 添加玩家绑定信息
        data.putDeep("owner", player.uniqueId.toString())
    }
}

动态显示内容

@EventHandler
fun onDisplayGenerate(event: ItemReleaseEvent.Display) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 获取物品数据
    val data = itemStream.getZaphkielData()
    val damage = data.getDeep("damage")?.asInt() ?: 0
    val owner = data.getDeep("owner")?.asString()
    
    // 动态添加显示内容
    event.addLore("damage_info", "&c伤害: &f$damage")
    
    if (owner != null) {
        val ownerName = Bukkit.getOfflinePlayer(UUID.fromString(owner)).name
        event.addLore("owner_info", "&7所有者: &f$ownerName")
    }
    
    // 添加时间戳
    val timestamp = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
    event.addLore("timestamp", "&8生成时间: $timestamp")
}

性能优化

事件过滤

@EventHandler
fun onItemInteract(event: ItemEvent.Interact) {
    val itemStream = event.itemStream
    val item = itemStream.getZaphkielItem()
    
    // 早期过滤,避免不必要的处理
    if (!item.id.startsWith("special_")) {
        return
    }
    
    // 只处理特定类型的物品
    when (item.id) {
        "special_weapon" -> handleWeaponInteract(event)
        "special_tool" -> handleToolInteract(event)
        "special_consumable" -> handleConsumableInteract(event)
    }
}

异步处理

@EventHandler
fun onItemBuild(event: ItemBuildEvent.Post) {
    val itemStream = event.itemStream
    val player = event.player
    
    // 将耗时操作移到异步线程
    submitAsync {
        val data = performExpensiveCalculation(itemStream, player)
        
        // 回到主线程更新数据
        submit {
            itemStream.getZaphkielData().putDeep("calculated_data", data)
        }
    }
}