自定义元数据开发
为 Zaphkiel 开发自定义元数据类型
概述
Zaphkiel 的元数据系统允许开发者创建自定义的元数据类型,为物品添加特殊功能。通过实现 Meta
接口并使用 @MetaKey
注解,你可以创建自己的元数据类型。
创建自定义元数据
1. 定义元数据类
创建一个继承 Meta
的类并使用 @MetaKey
注解:
@MetaKey("custom_effect")
class CustomEffectMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "custom_effect"
// 从配置中读取参数
private val effectType = config.getString("meta.custom_effect.type", "speed")
private val effectLevel = config.getInt("meta.custom_effect.level", 1)
private val effectDuration = config.getInt("meta.custom_effect.duration", 200)
override fun build(player: Player?, compound: ItemTag) {
// 在物品构建时执行的逻辑
// 这里可以修改物品的 NBT 数据
compound.putDeep("custom_effect.type", effectType)
compound.putDeep("custom_effect.level", effectLevel)
compound.putDeep("custom_effect.duration", effectDuration)
}
override fun build(event: ItemReleaseEvent) {
// 在物品释放时执行的逻辑
// 这里可以修改最终的 ItemStack
}
override fun build(itemMeta: ItemMeta) {
// 修改物品的 ItemMeta
// 例如添加特殊的 lore 或属性
}
override fun drop(player: Player?, compound: ItemTag) {
// 当元数据被移除时执行的清理逻辑
compound.removeDeep("custom_effect")
}
override fun drop(event: ItemReleaseEvent) {
// 物品释放时的清理逻辑
}
override fun drop(itemMeta: ItemMeta) {
// ItemMeta 的清理逻辑
}
}
2. 配置文件使用
在物品配置中使用自定义元数据:
magic_boots:
icon: diamond_boots
name:
item_name: '&b魔法靴子'
meta:
custom_effect:
type: "speed"
level: 2
duration: 300
custom_effect!!: # 锁定版本,强制更新
type: "jump_boost"
level: 1
duration: 200
元数据应用机制
构建时应用
元数据在物品构建过程中被应用:
@SubscribeEvent
fun onBuildPost(e: ItemBuildEvent.Post) {
e.itemStream.dropMeta.forEach {
dropMeta[it]?.drop(e.player, e.itemStream.sourceCompound)
}
e.item.meta.forEach {
if (it.locked || ItemSignal.UPDATE_CHECKED !in e.itemStream.signal) {
it.build(e.player, e.itemStream.sourceCompound)
}
}
e.itemStream.setZaphkielMetaHistory(e.item.meta.map { it.id })
}
释放时应用
元数据在物品转换为 ItemStack 时被应用:
@SubscribeEvent
fun onRelease(e: ItemReleaseEvent) {
val itemStream = e.itemStream
itemStream.dropMeta.forEach {
val meta = dropMeta[it]
if (meta != null) {
meta.drop(e)
meta.drop(e.itemMeta)
}
}
e.item.meta.forEach {
if (it.locked || ItemSignal.UPDATE_CHECKED !in itemStream.signal) {
it.build(e)
it.build(e.itemMeta)
}
}
}
高级元数据示例
自定义属性元数据
@MetaKey("custom_attributes")
class CustomAttributesMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "custom_attributes"
private val attributes = mutableMapOf<String, Double>()
init {
config.getConfigurationSection("meta.custom_attributes")?.let { section ->
section.getKeys(false).forEach { key ->
attributes[key] = section.getDouble(key)
}
}
}
override fun build(event: ItemReleaseEvent) {
val itemMeta = event.itemMeta
if (itemMeta is ItemMeta) {
// 添加自定义属性到 lore
val lore = itemMeta.lore?.toMutableList() ?: mutableListOf()
lore.add("")
lore.add("§6自定义属性:")
attributes.forEach { (name, value) ->
lore.add("§7• $name: §f$value")
}
itemMeta.lore = lore
}
}
override fun build(player: Player?, compound: ItemTag) {
// 将属性数据存储到 NBT
attributes.forEach { (name, value) ->
compound.putDeep("custom_attributes.$name", value)
}
}
}
技能冷却元数据
@MetaKey("skill_cooldown")
class SkillCooldownMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "skill_cooldown"
private val cooldownTime = config.getLong("meta.skill_cooldown.time", 5000L)
private val skillName = config.getString("meta.skill_cooldown.skill", "未知技能")
override fun build(player: Player?, compound: ItemTag) {
compound.putDeep("skill_cooldown.time", cooldownTime)
compound.putDeep("skill_cooldown.skill", skillName)
compound.putDeep("skill_cooldown.last_use", 0L)
}
override fun build(event: ItemReleaseEvent) {
val itemMeta = event.itemMeta
val compound = event.itemStream.sourceCompound
val lastUse = compound.getDeep("skill_cooldown.last_use")?.asLong() ?: 0L
val currentTime = System.currentTimeMillis()
val remainingCooldown = maxOf(0L, cooldownTime - (currentTime - lastUse))
if (remainingCooldown > 0) {
val lore = itemMeta.lore?.toMutableList() ?: mutableListOf()
lore.add("")
lore.add("§c技能冷却: §f${remainingCooldown / 1000}秒")
itemMeta.lore = lore
}
}
}
元数据历史管理
历史记录机制
系统维护元数据应用历史:
override fun getZaphkielMetaHistory(): List<String> {
if (isVanilla()) {
error("This item is not an extension item.")
}
return getZaphkielCompound()!![ItemKey.META_HISTORY.key]?.asList()?.map { it.asString() }?.toList() ?: emptyList()
}
override fun setZaphkielMetaHistory(meta: List<String>) {
if (isVanilla()) {
error("This item is not extension item.")
}
if (isLocked) {
error("This item is locked.")
}
getZaphkielCompound()!![ItemKey.META_HISTORY.key] = ItemTagList.of(*meta.map { ItemTagData(it) }.toTypedArray())
}
清理过期元数据
@MetaKey("cleanup_example")
class CleanupExampleMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "cleanup_example"
override fun drop(player: Player?, compound: ItemTag) {
// 清理所有相关的 NBT 数据
compound.removeDeep("cleanup_example")
compound.removeDeep("temp_data")
}
override fun drop(itemMeta: ItemMeta) {
// 清理 ItemMeta 中的相关数据
val lore = itemMeta.lore?.toMutableList() ?: return
lore.removeIf { it.contains("临时效果") }
itemMeta.lore = lore
}
}
最佳实践
1. 配置验证
@MetaKey("validated_meta")
class ValidatedMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "validated_meta"
private val value: Int
init {
val configValue = config.getInt("meta.validated_meta.value", 0)
if (configValue < 0 || configValue > 100) {
throw IllegalArgumentException("Value must be between 0 and 100, got: $configValue")
}
value = configValue
}
}
2. 性能优化
@MetaKey("optimized_meta")
class OptimizedMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "optimized_meta"
// 缓存计算结果
private val cachedResult by lazy {
expensiveCalculation()
}
override fun build(player: Player?, compound: ItemTag) {
// 使用缓存的结果
compound.putDeep("optimized.result", cachedResult)
}
private fun expensiveCalculation(): String {
// 复杂的计算逻辑
return "calculated_value"
}
}
3. 错误处理
@MetaKey("safe_meta")
class SafeMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "safe_meta"
override fun build(player: Player?, compound: ItemTag) {
try {
// 可能失败的操作
riskyOperation(compound)
} catch (e: Exception) {
// 记录错误但不中断物品构建
plugin.logger.warning("Failed to apply safe_meta: ${e.message}")
}
}
private fun riskyOperation(compound: ItemTag) {
// 风险操作
}
}
注册和管理
手动注册元数据
// 在插件启动时手动注册
val itemManager = Zaphkiel.api().getItemManager()
itemManager.registerMeta(CustomEffectMeta::class.java)
注销元数据
// 在插件关闭时注销
val itemManager = Zaphkiel.api().getItemManager()
itemManager.unregisterMeta(CustomEffectMeta::class.java)
调试和测试
调试元数据应用
@MetaKey("debug_meta")
class DebugMeta(config: ConfigurationSection) : Meta(config) {
override val id: String = "debug_meta"
override fun build(player: Player?, compound: ItemTag) {
info("Applying debug_meta for player: ${player?.name}")
info("Current compound: $compound")
// 应用
}