命令注册与自动补全对接指南

Updated 11 hours ago

SimpleInGameChat:命令注册与自动补全对接指南

本文面向其他模组作者,说明如何向 SimpleInGameChat 注册聊天命令,以及如何为命令提供 Tab 自动补全候选。

1. 前置条件

  • 你的模组需要引用 SimpleInGameChat.dll
  • 运行时需要确保 SimpleInGameChat 已加载(建议使用 BepInEx 依赖声明)

2. 命令系统概览

  • 触发前缀:/! 都会进入命令系统
  • 命令解析规则:
    • 输入以 /! 开头时,会解析第一个空格前的 token 作为命令名
    • 例如:/tp Alice!tp Alice
  • 命令分发入口:ChatCommandManager.TryHandleChatInput(...)
  • 命令注册入口:ChatCommandManager.Register(IChatCommand)

3. 注册一个命令

实现 IChatCommand

using System;
using System.Collections.Generic;
using SimpleInGameChat.Commands;
using SimpleInGameChat.Localization;

public sealed class MyCommand : IChatCommand
{
    // 命令名:输入 /mycmd 或 !mycmd 时触发
    public string Name => "mycmd";

    // 别名:输入 /alias 或 !alias 也会触发同一命令
    public IEnumerable<string> Aliases => new[] { "alias" };

    public bool TryExecute(ChatCommandContext context)
    {
        // context.RawInput:原始输入(含前缀)
        // context.Command:命令 token(不含前缀)
        // context.Args:参数数组(按空格拆分)
        // context.SenderClientId:发送者 clientId
        // context.Network:SimpleInGameChat 的网络管理器(可用于发系统消息、发网络请求等)

        if (context.Args.Length == 0)
        {
            context.Network.SendLocalSystemMessage(LocalizationManager.Instance.GetLocalizedText("ui.system_message", "缺少参数"));
            return true;
        }

        context.Network.SendLocalSystemMessage(LocalizationManager.Instance.GetLocalizedText("ui.system_message", $"收到参数:{string.Join(",", context.Args)}"));
        return true;
    }
}

在你的插件初始化时注册:

using BepInEx;
using SimpleInGameChat.Commands;

[BepInPlugin("com.yourname.yourmod", "YourMod", "1.0.0")]
[BepInDependency("SimpleInGameChat", BepInDependency.DependencyFlags.SoftDependency)]
public sealed class YourModPlugin : BaseUnityPlugin
{
    private void Awake()
    {
        ChatCommandManager.Register(new MyCommand());
    }
}

注意事项:

  • Register 可重复调用;同名或同别名会被后注册的覆盖
  • 不要求等到网络完全初始化后才注册命令,但命令执行时若依赖联机状态,请自行检查

4. 自动补全(Tab 候选)

4.1 自动补全行为

  • 当输入框打开时,Tab 会循环候选项并把候选应用到输入框
  • 候选最多显示 6 个(由聊天 UI 限制)
  • /! 前缀会保留:你输入的是 !mycmd,补全结果也会以 ! 开头

4.2 命令名补全(无需额外实现)

只要命令已通过 ChatCommandManager.Register 注册:

  • 输入 /m 会提示所有以 m 开头的命令名(及其别名)
  • Tab 会补全为 /<命令名> (末尾带空格,方便继续输入参数)

4.3 参数补全(实现 IChatCommandAutoComplete)

如果你希望在命令后面的参数阶段提供候选(例如玩家名、物品名、子命令等),让命令实现 IChatCommandAutoComplete

using System;
using System.Collections.Generic;
using SimpleInGameChat.Commands;

public sealed class MyCommand : IChatCommand, IChatCommandAutoComplete
{
    public string Name => "mycmd";
    public IEnumerable<string> Aliases => Array.Empty<string>();

    public bool TryExecute(ChatCommandContext context)
    {
        return true;
    }

    public IEnumerable<ChatAutoCompleteItem> GetAutoCompleteItems(ChatAutoCompleteContext context)
    {
        // context.Prefix:用户输入的前缀('/' 或 '!')
        // context.CommandToken:命令 token(不含前缀)
        // context.ArgsText:命令名后的整段参数文本(未拆分,保留空格)
        // context.SenderClientId / context.Network:与执行阶段一致

        string query = (context.ArgsText ?? string.Empty).Trim();

        // DisplayText:候选列表显示内容
        // ApplyText:按 Tab 时写回输入框的完整文本
        yield return new ChatAutoCompleteItem(
            displayText: "候选一",
            applyText: $"{context.Prefix}{context.CommandToken} 候选一"
        );

        yield return new ChatAutoCompleteItem(
            displayText: "候选二",
            applyText: $"{context.Prefix}{context.CommandToken} 候选二"
        );
    }
}

建议:

  • ApplyText 请返回“完整输入内容”(含前缀与命令名),这样 UI 不需要理解你的命令格式
  • 如果候选很多,请在命令内部自行排序/过滤(例如前缀匹配优先)

5. 常见问题

5.1 为什么候选里会出现默认玩家名(例如“玩家 0”)?

联机玩家名字通常是异步同步的。如果你做玩家名补全,建议只使用“已解析到真实名字”的数据源,并在后台触发请求补齐名字。

5.2 我能不能在候选里显示更丰富的信息(比如“名字 (ID)”)?

可以:

  • DisplayText 用于显示
  • ApplyText 用于写回

例如显示 Alice (12),但应用时填入 Alice