事件系统
AIOShop 提供了完整的事件系统,让开发者可以监听和干预商店交易。
事件类型
ShopPrePurchaseEvent
购买前置事件,在玩家购买商品之前触发,可以被取消。
触发时机:主线程,进入异步处理链之前
可取消:是
kotlin
class ShopPrePurchaseEvent(
val player: Player, // 购买玩家
val shop: UnifiedShop, // 商店实例
val item: ShopItem, // 商品实例
val amount: Int, // 购买数量
val price: Price // 单价(已考虑折扣)
) : AIOShopEvent(), Cancellable {
var cancelReason: String? = null // 取消原因
val totalPrice: Double // 总价格
get() = price.amount * amount
}使用示例:
kotlin
@EventHandler
fun onPrePurchase(event: ShopPrePurchaseEvent) {
val player = event.player
val item = event.item
val totalPrice = event.totalPrice
// 区域保护
if (isRestrictedArea(player.location)) {
event.isCancelled = true
event.cancelReason = "此区域禁止交易"
return
}
// 反作弊检测
if (isAbnormalPurchase(player, item, event.amount)) {
event.isCancelled = true
event.cancelReason = "检测到异常交易行为"
return
}
// 自定义权限检查
if (!hasCustomPermission(player, item)) {
event.isCancelled = true
event.cancelReason = "你没有购买此商品的权限"
}
}ShopPostPurchaseEvent
购买后置事件,在玩家成功购买商品后触发,不可取消。
触发时机:异步线程,交易完全完成后
可取消:否
kotlin
class ShopPostPurchaseEvent(
val transaction: Transaction, // 完整交易记录
val shop: UnifiedShop, // 商店实例
val item: ShopItem // 商品实例
) : AIOShopEvent() {
val player: Player? // 购买玩家(可能为 null)
get() = Bukkit.getPlayer(transaction.playerId)
val isAsync: Boolean // 是否在异步线程
get() = !Bukkit.isPrimaryThread()
val amount: Int // 购买数量
get() = transaction.amount
val totalPrice: Double // 总价格
get() = transaction.price
}使用示例:
kotlin
@EventHandler
fun onPostPurchase(event: ShopPostPurchaseEvent) {
val transaction = event.transaction
// Discord 通知
sendDiscordWebhook(
"**${transaction.playerName}** 购买了 **${event.item.displayName}** x${transaction.amount}"
)
// 任务系统
questManager.onPurchase(transaction.playerId, event.item.id, transaction.amount)
// 经济分析
economyAnalytics.recordPurchase(
shopId = event.shop.id,
itemId = event.item.id,
price = transaction.price,
timestamp = transaction.timestamp
)
// 数据库日志
database.insertTransactionLog(transaction)
}ShopPreSellEvent
出售前置事件,在玩家出售物品之前触发,可以被取消。
触发时机:主线程
可取消:是
kotlin
class ShopPreSellEvent(
val player: Player,
val shop: UnifiedShop,
val item: ShopItem,
val amount: Int,
val price: Price
) : AIOShopEvent(), Cancellable {
var cancelReason: String? = null
val totalPrice: Double
get() = price.amount * amount
}使用示例:
kotlin
@EventHandler
fun onPreSell(event: ShopPreSellEvent) {
// 检查出售冷却
if (isOnCooldown(event.player, "sell")) {
event.isCancelled = true
event.cancelReason = "出售操作冷却中"
return
}
// 自定义出售限制
val dailySold = getDailySoldAmount(event.player)
if (dailySold + event.amount > 1000) {
event.isCancelled = true
event.cancelReason = "已达到今日出售上限"
}
}ShopPostSellEvent
出售后置事件,在玩家成功出售物品后触发,不可取消。
触发时机:异步线程
可取消:否
kotlin
class ShopPostSellEvent(
val transaction: Transaction,
val shop: UnifiedShop,
val item: ShopItem
) : AIOShopEvent() {
val player: Player?
val isAsync: Boolean
val amount: Int
val totalPrice: Double
}使用示例:
kotlin
@EventHandler
fun onPostSell(event: ShopPostSellEvent) {
val transaction = event.transaction
// 更新成就
achievementManager.onSell(transaction.playerId, transaction.amount)
// 日志记录
logger.info("[出售] ${transaction.playerName}: ${event.item.id} x${transaction.amount} = ${transaction.price}")
}Transaction 对象
交易记录包含完整的交易信息:
kotlin
data class Transaction(
val id: Long, // 交易 ID
val playerId: UUID, // 玩家 UUID
val playerName: String, // 玩家名称
val shopId: String, // 商店 ID
val itemId: String, // 商品 ID
val type: TransactionType, // 交易类型(BUY/SELL)
val amount: Int, // 交易数量
val price: Double, // 总价格
val currency: String, // 货币类型
val timestamp: Long // 时间戳
)线程安全注意事项
前置事件(Pre)
- 在主线程触发
- 可以安全地操作 Bukkit API
- 可以取消事件
后置事件(Post)
- 在异步线程触发
- 操作 Bukkit API 需要切回主线程
- 不可取消事件
kotlin
@EventHandler
fun onPostPurchase(event: ShopPostPurchaseEvent) {
// 异步操作(安全)
database.saveTransaction(event.transaction)
// 需要切回主线程的操作
Bukkit.getScheduler().runTask(plugin) {
event.player?.sendTitle("购买成功", "感谢惠顾")
}
}完整示例插件
kotlin
class MyShopAddon : JavaPlugin(), Listener {
override fun onEnable() {
server.pluginManager.registerEvents(this, this)
logger.info("MyShopAddon 已加载")
}
@EventHandler(priority = EventPriority.HIGH)
fun onPrePurchase(event: ShopPrePurchaseEvent) {
// VIP 折扣
if (event.player.hasPermission("vip.discount")) {
// 通知玩家享受折扣
event.player.sendMessage("§a[VIP] 您享受 VIP 专属折扣!")
}
}
@EventHandler
fun onPostPurchase(event: ShopPostPurchaseEvent) {
// 首次购买奖励
if (isFirstPurchase(event.transaction.playerId)) {
Bukkit.getScheduler().runTask(this) {
event.player?.let { player ->
player.sendMessage("§6恭喜完成首次购买!获得 100 金币奖励!")
// 给予奖励...
}
}
}
}
private fun isFirstPurchase(playerId: UUID): Boolean {
// 检查数据库...
return false
}
}