Skip to content

GTCore 脚本系统

GTCore 脚本适合快速补玩法、写活动、做临时 GUI、调试物品和调用统一适配器。
脚本应该调用 GTCore 公开上下文和 SDK 工具,不要调用内部实现类。

目录

text
plugins/GTCore/scripts/
├─ groovy/
│  ├─ reward_menu.groovy
│  └─ tools.groovy
├─ js/
│  └─ example.js
└─ disabled/

Groovy 文件放进 groovy,JS 文件放进 js。不用的脚本移动到 disabled

开启脚本

yaml
scripts:
  groovy:
    enabled: true
  js:
    enabled: false

重载脚本:

text
/gtcore reloadscripts

输出里需要看到对应引擎为 true。如果 groovy=false,说明 Groovy 引擎没有启用或依赖没有加载成功。

脚本上下文

脚本默认可用:

名称用途
ctx当前脚本上下文,注册命令、事件、任务、GUI、动作
pluginGTCore 插件实例
GTCore统一 API 入口
GTGuiGUI 工具
GTAction动作工具
GTMatcherRule匹配规则工具

常用 ctx 方法:

方法用途
ctx.registerCommand(...)注册命令
ctx.event(...)监听 Bukkit 事件
ctx.timer(...)定时任务
ctx.later(...)延迟任务
ctx.action(...)注册自定义动作
ctx.variable(...)注册表达式变量
ctx.item(...)创建统一物品
ctx.giveItem(...)发放统一物品
ctx.takeItem(...)扣除统一物品
ctx.openMenu(...)打开 GUI
ctx.openDialog(...)打开确认弹窗
ctx.input(...)输入文本
ctx.runActions(...)执行动作列表
ctx.onUnload(...)脚本卸载清理

第一个 Groovy 脚本

文件:

text
plugins/GTCore/scripts/groovy/hello.groovy

内容:

groovy
import com.rusbrook.gtcore.sdk.CommandExecutorHandler
import org.bukkit.entity.Player

ctx.registerCommand("gthello", [] as List, "", "测试脚本命令", "/gthello", { sender, label, args ->
    if (sender instanceof Player) {
        sender.sendMessage("§aGTCore 脚本已运行。")
    } else {
        sender.sendMessage("GTCore 脚本已运行。")
    }
    return true
} as CommandExecutorHandler, null)

重载:

text
/gtcore reloadscripts

测试:

text
/gthello

命令执行动作

如果一个命令只需要执行动作列表,可以用 commandActions

groovy
ctx.commandActions(
    "starter",
    [
        "[item] DIAMOND*3",
        "[money] give 100",
        "[message] &a已领取新手奖励。"
    ],
    [] as List,
    "",
    "领取新手奖励",
    "/starter"
)

适合礼包、传送、临时活动奖励。

打开 GUI

groovy
import com.rusbrook.gtcore.sdk.CommandExecutorHandler
import com.rusbrook.gtcore.sdk.GTGui
import com.rusbrook.gtcore.sdk.GTAction
import org.bukkit.entity.Player

ctx.registerCommand("gtmenu", [] as List, "", "打开菜单", "/gtmenu", { sender, label, args ->
    if (!(sender instanceof Player)) return true
    def player = sender as Player

    def menu = GTGui.menu("&8脚本菜单")
        .rows(3)
        .border(GTGui.material("GRAY_STAINED_GLASS_PANE", " "))
        .button(13, GTGui.button(GTGui.material("CHEST", "&a领取奖励", ["&7点击领取"]))
            .actions([
                GTAction.item("DIAMOND", 3),
                GTAction.message("&a领取成功。"),
                GTAction.close()
            ])
            .build())
        .build()

    ctx.openMenu(player, menu)
    return true
} as CommandExecutorHandler, null)

使用物品库

创建物品:

groovy
def vanilla = ctx.item("DIAMOND", player, 3)
def niItem = ctx.item("ni:starter_sword", player, 1)
def mmItem = ctx.item("mm:BossKey", player, 1)
def ceItem = ctx.item("ce:geartech:coin", player, 1)

发物品:

groovy
ctx.giveItem(player, "ni:starter_sword", 1)

扣物品:

groovy
def ok = ctx.takeItem(player, "mm:BossKey", 1, false)
if (!ok) {
    player.sendMessage("§c需要 1 个副本钥匙。")
}

统计数量:

groovy
def amount = ctx.countItem(player, "DIAMOND", false)
player.sendMessage("§7背包里有钻石: §e" + amount)

监听事件

监听玩家退出并清理缓存:

groovy
import java.util.function.Consumer
import org.bukkit.event.player.PlayerQuitEvent

def cache = [:]

ctx.event("org.bukkit.event.player.PlayerQuitEvent", "NORMAL", false, { event ->
    event = event as PlayerQuitEvent
    cache.remove(event.player.uniqueId)
} as Consumer)

监听伤害事件:

groovy
import java.util.function.Consumer
import org.bukkit.event.entity.EntityDamageByEntityEvent
import org.bukkit.entity.Player

ctx.event("org.bukkit.event.entity.EntityDamageByEntityEvent", "NORMAL", false, { event ->
    event = event as EntityDamageByEntityEvent
    if (event.damager instanceof Player) {
        event.damager.sendMessage("§7本次伤害: §e" + event.damage)
    }
} as Consumer)

定时任务

每 5 秒提示一次在线人数:

groovy
import org.bukkit.Bukkit

def task = ctx.timer(0L, 100L, false, {
    Bukkit.getOnlinePlayers().each { player ->
        player.sendMessage("§7当前在线: §e" + Bukkit.getOnlinePlayers().size())
    }
} as Runnable)

ctx.onUnload({
    task.cancel()
} as Runnable)

ctx.timer 注册的任务会在脚本卸载时自动清理,手动保存引用是为了需要提前取消时更方便。

自定义动作

注册一个 [fire_reward] 动作:

groovy
import com.rusbrook.gtcore.sdk.ActionExecutor

ctx.action("fire_reward", { actionCtx ->
    def player = actionCtx.player
    if (player == null) return false
    ctx.giveItem(player, "BLAZE_ROD", 1)
    player.sendMessage("§6获得火焰奖励。")
    return true
} as ActionExecutor)

之后任何 GUI 或配置都可以调用:

text
[fire_reward]

自定义变量

注册一个表达式变量:

groovy
import com.rusbrook.gtcore.sdk.ExpressionVariable

ctx.variable("online_count", { variableCtx ->
    return org.bukkit.Bukkit.getOnlinePlayers().size()
} as ExpressionVariable)

动作中使用:

text
[message] &7当前在线: <online_count>

数据文件

脚本私有数据目录在:

text
plugins/GTCore/scripts-data/<脚本名>/

读写文本:

groovy
def count = (ctx.readText("count.txt", "0") as String).toInteger()
count++
ctx.writeText("count.txt", count.toString())

所有路径都会限制在脚本自己的数据目录内。

卸载清理

重载脚本时必须清理自己创建的额外状态:

groovy
def cache = [:]

ctx.onUnload({
    cache.clear()
    ctx.info("缓存已清理")
} as Runnable)

命令、事件、任务、GUI 会由 GTCore 按脚本归属自动清理;自己保存的集合、临时文件、外部对象需要在 onUnload 中处理。

排错

MissingMethodException

说明脚本调用了不存在的方法,或 Groovy 没有匹配到正确重载。
命令、事件、动作这类接口建议显式导入并强转:

groovy
import com.rusbrook.gtcore.sdk.CommandExecutorHandler

ctx.registerCommand("test", [] as List, "", "说明", "/test", { sender, label, args ->
    return true
} as CommandExecutorHandler, null)

engine=false

检查:

  1. scripts.groovy.enabled 是否为 true
  2. 依赖是否下载完成。
  3. Java 版本是否兼容当前脚本引擎。
  4. 修改开关后是否执行了重载或重启。

脚本没有执行

检查:

  1. 文件是否在 plugins/GTCore/scripts/groovy/js/
  2. 后缀是否正确。
  3. /gtcore reloadscripts 是否显示加载数量。
  4. 控制台是否有编译错误。