Skip to content

注册指令

MSL 允许插件注册自定义指令,玩家可以在游戏中通过聊天或命令行触发这些指令。本章将详细介绍指令注册机制和使用方法。

指令概述

MSL 支持两种类型的自定义指令:

  1. 聊天指令:以 ! 开头,玩家在聊天中输入即可触发
  2. 命令指令:以 / 开头,玩家执行命令时触发

基本用法

注册简单指令

使用 plugin_registerCommand 注册指令:

javascript
// 注册 !ping 指令
plugin_registerCommand("!ping", (player) => {
    plugin_executeCommand(`say ${player} 请求了 ping!`);
});

玩家在游戏中输入:

!ping

服务器输出:

[Steve] 请求了 ping!

指令格式

指令表达式格式:

<prefix><command> [参数...]
  • prefix:指令前缀,必须是 !/
  • command:指令名称
  • 参数:可选参数,使用 <param> 格式

带参数的指令

单参数指令

javascript
// 注册 !kick <player> 指令
plugin_registerCommand("!kick <player>", (player, target) => {
    plugin_executeCommand(`kick ${target} 被 ${player} 踢出服务器`);
    plugin_log("INFO", `${player} 踢出了 ${target}`);
});

玩家输入:

!kick Alex

多参数指令

javascript
// 注册 !ban <player> <reason> 指令
plugin_registerCommand("!ban <player> <reason>", (player, target, reason) => {
    plugin_executeCommand(`ban ${target} ${reason}`);
    plugin_log("INFO", `${player} 封禁了 ${target},原因:${reason}`);
});

玩家输入:

!ban Alex 使用外挂

混合固定文本和参数

javascript
// 注册 !tp to <player> 指令
plugin_registerCommand("!tp to <player>", (player, target) => {
    plugin_executeCommand(`tp ${player} ${target}`);
    plugin_log("INFO", `${player} 传送到 ${target}`);
});

玩家输入:

!tp to Alex

注意:to 是固定文本,必须完全匹配。

指令匹配规则

MSL 使用严格的指令匹配规则:

1. 前缀匹配

指令前缀必须完全匹配:

javascript
plugin_registerCommand("!ping", ...);

// 匹配:!ping
// 不匹配:/ping, ping

2. 名称匹配

指令名称区分大小写:

javascript
plugin_registerCommand("!Ping", ...);

// 匹配:!Ping
// 不匹配:!ping, !PING

3. 参数数量匹配

参数数量必须完全匹配:

javascript
plugin_registerCommand("!kick <player>", ...);

// 匹配:!kick Alex
// 不匹配:!kick, !kick Alex reason

4. 固定文本匹配

固定文本必须完全匹配:

javascript
plugin_registerCommand("!tp to <player>", ...);

// 匹配:!tp to Alex
// 不匹配:!tp Alex, !tp from Alex

实用示例

帮助系统

javascript
// 注册 !help 指令
plugin_registerCommand("!help", (player) => {
    const helpMessages = [
        "========== 服务器帮助 ==========",
        "!help - 显示帮助信息",
        "!online - 查看在线玩家",
        "!home - 传送到家",
        "!sethome - 设置家",
        "================================"
    ];
    
    helpMessages.forEach(msg => {
        plugin_executeCommand(`tellraw ${player} {"text":"${msg}","color":"yellow"}`);
    });
});

在线玩家查询

javascript
// 注册 !online 指令
plugin_registerCommand("!online", (player) => {
    plugin_executeCommand("list", (lines) => {
        lines.forEach(line => {
            if (line.includes("players online")) {
                plugin_executeCommand(`tellraw ${player} {"text":"${line}","color":"green"}`);
            }
        });
    });
});

家系统

javascript
// 设置家
plugin_registerCommand("!sethome", (player) => {
    // 注意:这里需要通过其他方式获取玩家坐标
    // 可以通过监听玩家位置或使用其他插件配合
    
    plugin_executeCommand(`tellraw ${player} {"text":"家已设置!","color":"green"}`);
});

// 回家
plugin_registerCommand("!home", (player) => {
    const homes = plugin_pull("playerHomes") || {};
    if (homes[player]) {
        const home = homes[player];
        plugin_executeCommand(`tp ${player} ${home.x} ${home.y} ${home.z}`);
        plugin_executeCommand(`tellraw ${player} {"text":"欢迎回家!","color":"green"}`);
    } else {
        plugin_executeCommand(`tellraw ${player} {"text":"你还没有设置家!使用 !sethome 设置","color":"red"}`);
    }
});

私聊系统

javascript
// 注册 !msg <player> <message> 指令
plugin_registerCommand("!msg <player> <message>", (sender, target, message) => {
    // 存储私聊消息
    const privateMessages = plugin_pull("privateMessages") || {};
    if (!privateMessages[target]) {
        privateMessages[target] = [];
    }
    privateMessages[target].push({
        from: sender,
        message: message,
        time: new Date().toISOString()
    });
    plugin_push("privateMessages", privateMessages);
    
    // 发送消息给目标玩家
    plugin_executeCommand(`tellraw ${target} {"text":"[私聊] ${sender}: ${message}","color":"light_purple"}`);
    plugin_executeCommand(`tellraw ${sender} {"text":"[私聊] -> ${target}: ${message}","color":"light_purple"}`);
});

管理员指令

javascript
// 注册 !admin <action> <player> 指令
plugin_registerCommand("!admin <action> <player>", (player, action, target) => {
    // 检查权限(这里简化处理,实际应该检查玩家权限)
    const admins = ["Steve", "Admin"];
    if (!admins.includes(player)) {
        plugin_executeCommand(`tellraw ${player} {"text":"你没有权限执行此命令","color":"red"}`);
        return;
    }
    
    switch (action.toLowerCase()) {
        case "kick":
            plugin_executeCommand(`kick ${target} 被管理员踢出`);
            break;
        case "ban":
            plugin_executeCommand(`ban ${target} 被管理员封禁`);
            break;
        case "op":
            plugin_executeCommand(`op ${target}`);
            break;
        default:
            plugin_executeCommand(`tellraw ${player} {"text":"未知操作: ${action}","color":"red"}`);
    }
});

指令权限控制

MSL 本身不提供权限系统,但你可以通过以下方式实现简单的权限控制:

基于玩家名的权限

javascript
const admins = ["Steve", "Admin", "Owner"];

plugin_registerCommand("!admin", (player) => {
    if (!admins.includes(player)) {
        plugin_executeCommand(`tellraw ${player} {"text":"权限不足","color":"red"}`);
        return;
    }
    
    // 执行管理员操作
    plugin_executeCommand("say 管理员指令已执行");
});

基于配置的权限

javascript
// 在插件中定义权限配置
const permissions = {
    "Steve": ["admin", "moderator"],
    "Alex": ["moderator"],
    "default": ["player"]
};

function hasPermission(player, permission) {
    const playerPerms = permissions[player] || permissions["default"];
    return playerPerms.includes(permission);
}

plugin_registerCommand("!ban <player>", (player, target) => {
    if (!hasPermission(player, "admin")) {
        plugin_executeCommand(`tellraw ${player} {"text":"权限不足","color":"red"}`);
        return;
    }
    
    plugin_executeCommand(`ban ${target}`);
});

权限节点

TIP

MSL正如原版mc服务器一样,不默认提供权限节点管理系统。你需要在MSL中安装类似于LuckPerms的插件来管理权限节点。

权限节点的全局数据键名都应该为permission:a.b.c...,即开头应为permission:,后续部分自行添加,但应保证条理。

权限节点机制应为:①MSL启动,拉起权限节点插件->②权限节点插件读取数据,将不同权限节点以及其对应的玩家名通过plugin_push推送到全局数据中->③用户调用某插件的指令->④插件通过plugin_pull拉取权限节点的玩家列表->⑤判断玩家是否具有权限并做出响应。

最佳实践

1. 指令命名规范

使用有意义的前缀避免冲突:

javascript
// 推荐:使用插件名作为前缀
plugin_registerCommand("!myplugin help", ...);
plugin_registerCommand("!myplugin reload", ...);

// 不推荐:通用名称可能冲突
plugin_registerCommand("!help", ...);

2. 错误处理

在指令回调中添加错误处理:

javascript
plugin_registerCommand("!kick <player>", (player, target) => {
    try {
        plugin_executeCommand(`kick ${target}`);
        plugin_log("INFO", `${player} 踢出了 ${target}`);
    } catch (error) {
        plugin_log("ERROR", `执行踢出指令失败: ${error.message}`);
        plugin_executeCommand(`tellraw ${player} {"text":"执行失败","color":"red"}`);
    }
});

3. 反馈信息

为玩家提供清晰的反馈:

javascript
plugin_registerCommand("!home", (player) => {
    const homes = plugin_pull("playerHomes") || {};
    if (homes[player]) {
        plugin_executeCommand(`tp ${player} ${homes[player].x} ${homes[player].y} ${homes[player].z}`);
        plugin_executeCommand(`tellraw ${player} {"text":"已传送到你的家","color":"green"}`);
    } else {
        plugin_executeCommand(`tellraw ${player} {"text":"你还没有设置家","color":"yellow"}`);
        plugin_executeCommand(`tellraw ${player} {"text":"使用 !sethome 设置你的家","color":"yellow"}`);
    }
});

4. 日志记录

记录指令使用情况:

javascript
plugin_registerCommand("!ban <player> <reason>", (player, target, reason) => {
    // 记录日志
    plugin_log("INFO", `[指令] ${player} 封禁了 ${target},原因:${reason}`);
    
    // 存储到全局数据
    const banLog = plugin_pull("banLog") || [];
    banLog.push({
        operator: player,
        target: target,
        reason: reason,
        time: new Date().toISOString()
    });
    plugin_push("banLog", banLog);
    
    // 执行封禁
    plugin_executeCommand(`ban ${target} ${reason}`);
});

下一步