Skip to content

工具集(util 包 + 服务)

导航:文档首页 · 目录 · API 概览 · 模块系统 · 术语表

QinhCoreLib(QCL)在 util 包及配套服务中提供了一整套通用工具。它们覆盖调度、特效、物品、坐标、服务端兼容、文本、全息与动态装配等高频场景,子插件可以直接拿来即用,不必重复造轮子。

本页按工具类分节,每节给出方法表与典型用法代码示例。所有代码示例均为照抄即用,标识符大小写敏感。

全局约定(务必先读)

  1. Runnable / Supplier,不要直接传 Kotlin lambda。 QCL 的调度 API(TaskSchedulerThrottledExecutor 等)形参类型是 Java 的 RunnableSupplier<T>。如果从 Kotlin 子插件直接以 SAM 转换方式传入裸 lambda,跨插件类加载时可能触发 LinkageError。请显式包成 Runnable { ... } / Supplier { ... },或在 Java 中正常传 lambda。

  2. Folia 兼容。TaskScheduler 基于 Bukkit 调度器封装,兼容 Folia。请始终通过 TaskScheduler 调度,而不是自己 Bukkit.getScheduler()

  3. MiniMessage 支持。 文本类(TextUtilHologramManagerAssemblySystem 等)均支持 MiniMessage 标签、旧版 & 颜色码、§ 颜色码与纯文本,自动识别转换为 Component

  4. 多名降级。ServerCompatsound(...) / particle(...) / material(...) / resolveSound / resolvePotionEffectType 接受多个候选名,按顺序尝试解析,命中第一个有效项,跨版本更稳。


TaskScheduler(调度)

封装 Bukkit 调度器,兼容 Folia。所有方法以 Runnable / Supplier 为参,避免 Kotlin lambda 的 LinkageError

方法说明
runSync(Runnable)主线程立即执行
runSyncLater(delay, Runnable)主线程延迟 delay tick 执行
runSyncRepeating(delay, period, Runnable)主线程定时重复执行
runAsync(Runnable)异步线程立即执行
runAsyncLater(delay, Runnable)异步线程延迟执行
runAsyncRepeating(delay, period, Runnable)异步线程定时重复执行
supplySync<T>(Supplier<T>): CompletableFuture<T>主线程取值,返回 CompletableFuture
supplyAsync<T>(Supplier<T>): CompletableFuture<T>异步线程取值,返回 CompletableFuture

典型用法

kotlin
// 主线程立即执行
TaskScheduler.runSync(Runnable {
    player.sendMessage("已在主线程执行")
})

// 延迟 20 tick(1 秒)后执行
TaskScheduler.runSyncLater(20L, Runnable {
    player.health = player.maxHealthValue()
})

// 每 5 tick 重复一次
val taskRef = TaskScheduler.runSyncRepeating(0L, 5L, Runnable {
    EffectUtils.spawnParticle(loc, Particle.HEART, 1)
})

// 异步计算后回主线程使用结果
TaskScheduler.supplyAsync(Supplier {
    heavyDatabaseQuery()  // 异步耗时操作
}).thenAccept { result ->
    TaskScheduler.runSync(Runnable {
        player.sendMessage("查询结果:$result")
    })
}

ThrottledExecutor(节流执行器)

按键节流:相同 keythrottleMs 内只执行一次。

方法说明
ThrottledExecutor(throttleMs)构造,指定节流间隔(毫秒)
execute(key, Runnable)若该 key 未在节流窗口内,则执行
clear()清空所有节流记录
kotlin
val throttle = ThrottledExecutor(200L) // 200ms 节流

// 高频事件(如移动)里防止刷屏
throttle.execute(player.uniqueId.toString(), Runnable {
    player.sendActionBar("移动中…")
})

CooldownManager(冷却管理)

按键冷却,常用于技能、交互冷却。

方法说明
hasCooldown(key)是否处于冷却中
getRemaining(key)剩余冷却时间
setCooldown(key, duration, unit)设置冷却
removeCooldown(key)移除某键冷却
clear()清空全部冷却
kotlin
val cd = CooldownManager()

val key = player.uniqueId.toString()
if (cd.hasCooldown(key)) {
    player.sendMessage("还需等待 ${cd.getRemaining(key)}")
    return
}
cd.setCooldown(key, 3, TimeUnit.SECONDS)
// 释放技能…

EffectUtils(特效)

声音与粒子的统一入口,附常用预置(Presets)。

方法说明
playSound(loc, ...)在坐标处播放声音
playSoundForPlayer(player, ...)仅对该玩家播放声音
playSoundForAll(...)对全服播放声音
spawnParticle(loc, particle, count)在坐标处生成粒子
spawnParticleForPlayer(player, ...)仅对该玩家显示粒子
spawnColoredDust(loc, color, ...)生成彩色尘埃粒子
spawnCircle(...)生成圆形粒子
spawnHelix(...)生成螺旋粒子
spawnLine(...)生成直线粒子

预置(Presets)

EffectUtils.Presets 提供一键场景特效,参数为坐标 loc

success(loc) / error(loc) / warning(loc) / info(loc) / click(loc) / plant(loc) / harvest(loc) / breakBlock(loc)

kotlin
// 成功特效
EffectUtils.Presets.success(player.location)

// 圆形粒子环
EffectUtils.spawnCircle(player.location, Particle.FLAME, /* 半径、点数等 */)

// 仅给单个玩家放声音
EffectUtils.playSoundForPlayer(player, Sound.ENTITY_PLAYER_LEVELUP)

ItemUtils(物品)

物品创建与编辑的便捷封装。

方法说明
isEmpty(item) / isNotEmpty(item)判空(含 AIR 与 null)
createItem(material, amount, name, lore, cmd)一次性创建带名/Lore/CustomModelData 的物品
setDisplayName(item, name) / getDisplayName(item)显示名读写
setLore(item, lore) / getLore(item) / addLoreLine(item, line)Lore 读写与追加
setCustomModelData(item, cmd) / getCustomModelData(item) / hasCustomModelData(item)CustomModelData 读写与判断
isSimilar(a, b) / compareWithNbt(a, b)相似比较 / 带 NBT 比较
clone(item, amount?)克隆物品(可指定数量)
takeItem(item, amount)扣减数量
kotlin
val sword = ItemUtils.createItem(
    Material.DIAMOND_SWORD,
    1,
    "<gold>秦淮之刃",          // 支持 MiniMessage
    listOf("<gray>一把好剑"),
    100100                     // CustomModelData
)

ItemUtils.addLoreLine(sword, "<yellow>已强化")

if (ItemUtils.isNotEmpty(sword) && ItemUtils.hasCustomModelData(sword)) {
    val cloned = ItemUtils.clone(sword, 2)
}

LocationUtils(坐标)

坐标序列化、计算与范围查询。

方法说明
serialize(loc) / deserialize(world, x, y, z, yaw, pitch)坐标序列化/反序列化
serializeList(...) / deserializeList(...)列表序列化(分号分隔)
getBlockLocation(loc) / getCenterLocation(loc)方块坐标 / 方块中心坐标
distance(a, b) / distanceSquared(a, b)距离 / 距离平方
isSameBlock(a, b)是否同一方块
getDirection(from, to) / lookAt(loc, target)方向向量 / 朝向目标
getNearbyLocations(...) / getNearbyBlocks(...)附近坐标 / 附近方块
isInRange(a, b, range)是否在范围内
getChunkKey(loc)区块键
kotlin
val serialized = LocationUtils.serialize(player.location)
// 列表用分号分隔
val listStr = LocationUtils.serializeList(spawnPoints)

val center = LocationUtils.getCenterLocation(block.location)
if (LocationUtils.isInRange(player.location, target, 5.0)) {
    val dir = LocationUtils.getDirection(player.location, target)
}

ServerCompat(服务端兼容)

跨平台、跨版本兼容层。提供平台探测、版本校验与多名降级解析。

方法 / 成员说明
detectPlatform() / platformLabel()探测平台 / 平台标签
bukkitVersionLabel() / parseBukkitVersion()Bukkit 版本标签 / 解析
pluginVersion(plugin)插件版本
validateServer(logger)校验服务端环境
validateJava(...)校验 Java(要求 ≥ 25)
validateMinecraftVersion(...)校验 Minecraft(要求 ≥ 1.21.11)
platform当前平台
supportsPluginLibraries是否支持 plugin libraries
supportsAsyncChatEvent是否支持异步聊天事件
resolveSound(...) / resolvePotionEffectType(...)解析声音 / 药水效果(多名降级)
sound(vararg) / particle(vararg) / material(vararg)多名降级解析声音/粒子/材质
ATTR_MAX_HEALTH属性常量
applyMaxStackSize(...)应用最大堆叠数
playBlockStepEffect(...)播放方块脚步特效

多名降级

kotlin
// 不同版本中材质名可能不同,按顺序尝试,命中第一个有效项
val mat = ServerCompat.material("GRASS_BLOCK", "GRASS")
val snd = ServerCompat.sound("BLOCK_NOTE_BLOCK_PLING", "NOTE_PLING")
val particle = ServerCompat.particle("DUST", "REDSTONE")

// 启动期环境校验
ServerCompat.validateServer(logger)   // Java ≥ 25、MC ≥ 1.21.11

TextUtil(文本,单数)

文本到 Component 的转换与彩色输出。toComponent 自动识别 MiniMessage / 旧版 & 码 / § 码 / 纯文本。

方法说明
toComponent(text)文本 → Component(自动识别格式)
colored(text)上色
sendColored(target, text)发送彩色消息
logColored(text)彩色日志
broadcastColored(text)彩色广播
applyItemDisplay(meta, name, lore)ItemMeta 套用名与 Lore
showColoredTitle(player, text, fadeIn, stay, fadeOut)显示彩色标题

Extensions.kt 扩展函数

扩展说明
String.toComponent()字符串 → Component
String.colored()字符串上色
String.parseMiniMessage()解析 MiniMessage
Player.sendColoredMessage(text)给玩家发彩色消息
String.replacePlaceholders(vararg pairs)替换占位符
Player.maxHealthValue()取玩家最大生命值
kotlin
import com.qinhuai.corelib.util.toComponent
import com.qinhuai.corelib.util.colored
import com.qinhuai.corelib.util.sendColoredMessage
import com.qinhuai.corelib.util.replacePlaceholders
import com.qinhuai.corelib.util.maxHealthValue

player.sendColoredMessage("<gold>欢迎回来")

val title = "你好 %name%".replacePlaceholders("%name%" to player.name)
TextUtil.showColoredTitle(player, "<rainbow>胜利", 10, 40, 10)

val hp = player.maxHealthValue()

TextUtils(文本工具,复数)

格式化与字符串处理工具。

方法说明
formatNumber(double, 小数位) / formatNumber(int)数字格式化
formatTime(ms)毫秒 → 1小时30分45秒
formatTimeCompact(ms)毫秒 → 紧凑时间
joinList(list, sep, lastSep)拼接列表(含末项分隔符)
capitalize(s) / toTitleCase(s)首字母大写 / 标题式
limitLength(s, n)截断长度
stripColors(s)去颜色码
countOccurrences(s, sub)子串出现次数
levenshteinDistance(a, b)编辑距离
findSimilar(...)模糊匹配
kotlin
TextUtils.formatNumber(1234.5678, 2)  // "1234.57"
TextUtils.formatTime(5445000L)        // "1小时30分45秒"
TextUtils.joinList(listOf("甲", "乙", "丙"), "、", " 和 ")  // "甲、乙 和 丙"

// 输错命令时给出近似建议
val guess = TextUtils.findSimilar(input, validCommands)

HologramManager(全息)

基于 ArmorStand 的全息文字。支持 MiniMessage,行高 0.25。被附加到实体上时,每秒自动重绑跟随。

HologramManager 方法

方法说明
create(id, location, vararg lines)在坐标创建全息
createAsPassenger(id, entity, offsetY, vararg lines)作为实体乘客创建(跟随实体)
get(id) / remove(id) / removeAll() / getAll()取/移除/全移除/取全部
showTemporary(location, text, durationTicks)临时全息(到时自动消失)
showPlayerBubble(player, text, fadeIn, stay, fadeOut)玩家头顶气泡

Hologram 实例方法

方法说明
setLine(index, text) / addLine(text) / removeLine(index)行编辑
getLines() / clearLines()取所有行 / 清空
update()刷新显示
setPassenger(entity, offsetY) / removePassenger()绑定/解绑实体乘客
show() / hide()显示 / 隐藏
teleport(location)传送
delete()删除
startRepairTask() / stopRepairTask()启/停自动重绑任务
kotlin
val holo = HologramManager.create(
    "shop-1",
    shopLocation,
    "<gold>秦淮商店",
    "<gray>右键购买"
)
holo.addLine("<yellow>库存充足")
holo.update()

// 头顶气泡
HologramManager.showPlayerBubble(player, "<aqua>升级了!", 5, 40, 10)

// 临时提示,60 tick 后消失
HologramManager.showTemporary(loc, "<green>+10 金币", 60)

// 跟随实体
val mobHolo = HologramManager.createAsPassenger("boss-hp", boss, 2.5, "<red>BOSS 血量")

AssemblySystem(动态装配)

动态物品显示分层系统:把名称、Lore 等显示拆成可叠加的 DisplayLayer,按 priority 升序应用。

核心类型

  • DisplayLayer 接口:priorityapply(meta, AssemblyContext)
  • AssemblyContext(variables):携带变量上下文。
  • ItemAssemblyaddLayer(layer)apply(item, context): ItemStack
  • 预置层:
    • NameLayer(priority) { ctx -> String }
    • LoreLayer(priority) { ctx -> List<String> }
kotlin
val assembly = ItemAssembly()

assembly.addLayer(NameLayer(0) { ctx ->
    "<gold>${ctx.variables["itemName"]}"
})
assembly.addLayer(LoreLayer(10) { ctx ->
    listOf(
        "<gray>等级:${ctx.variables["level"]}",
        "<yellow>攻击:${ctx.variables["atk"]}"
    )
})

val context = AssemblyContext(mapOf(
    "itemName" to "秦淮之刃",
    "level" to "5",
    "atk" to "120"
))

val finalItem: ItemStack = assembly.apply(baseItem, context)

自定义层:实现 DisplayLayer 接口,重写 priorityapply(meta, ctx),再 addLayer 即可。所有层按 priority 从小到大依次作用于同一 ItemMeta


继续阅读