Command Registration and Auto-Complete Integration Guide

Updated 11 hours ago

This document is intended for other mod authors, explaining how to register chat commands with SimpleInGameChat and how to provide Tab auto-complete candidates for commands.

1. Prerequisites

  • Your mod needs to reference SimpleInGameChat.dll.
  • Ensure SimpleInGameChat is loaded at runtime (using BepInEx dependency declaration is recommended).

2. Command System Overview

  • Trigger Prefixes: Both / and ! will enter the command system.
  • Command Parsing Rules:
    • When input starts with / or !, the token before the first space is parsed as the command name.
    • Example: /tp Alice, !tp Alice.
  • Command Dispatch Entry Point: ChatCommandManager.TryHandleChatInput(...).
  • Command Registration Entry Point: ChatCommandManager.Register(IChatCommand).

3. Registering a Command

Implement IChatCommand:

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

public sealed class MyCommand : IChatCommand
{
    // Command Name: Triggered when inputting /mycmd or !mycmd
    public string Name => "mycmd";

    // Aliases: /alias or !alias will also trigger the same command
    public IEnumerable<string> Aliases => new[] { "alias" };

    public bool TryExecute(ChatCommandContext context)
    {
        // context.RawInput: Original input (including prefix)
        // context.Command: Command token (excluding prefix)
        // context.Args: Argument array (split by space)
        // context.SenderClientId: Sender's clientId
        // context.Network: Network manager of SimpleInGameChat (can be used to send system messages, network requests, etc.)

        if (context.Args.Length == 0)
        {
            context.Network.SendLocalSystemMessage(LocalizationManager.Instance.GetLocalizedText("ui.system_message", "Missing arguments"));
            return true;
        }

        context.Network.SendLocalSystemMessage(LocalizationManager.Instance.GetLocalizedText("ui.system_message", $"Received arguments: {string.Join(",", context.Args)}"));
        return true;
    }
}

Register during your plugin initialization:

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());
    }
}

Notes:

  • Register can be called repeatedly; same names or aliases will be overwritten by later registrations.
  • It is not required to wait for the network to be fully initialized before registering commands, but if command execution relies on online status, please check it yourself.

4. Auto-Complete (Tab Candidates)

4.1 Auto-Complete Behavior

  • When the input box is open, Tab cycles through candidates and applies the candidate to the input box.
  • A maximum of 6 candidates are displayed (limited by Chat UI).
  • / and ! prefixes are preserved: if you input !mycmd, the completion result will also start with !.

4.2 Command Name Completion (No Extra Implementation Required)

As long as the command is registered via ChatCommandManager.Register:

  • Inputting /m will suggest all command names (and their aliases) starting with m.
  • Tab will complete it as /<command_name> (with a trailing space for continuing parameter input).

4.3 Parameter Completion (Implement IChatCommandAutoComplete)

If you wish to provide candidates during the parameter stage after the command (e.g., player names, item names, sub-commands), let the command implement 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: User input prefix ('/' or '!')
        // context.CommandToken: Command token (excluding prefix)
        // context.ArgsText: Full argument text after command name (unsplit, preserving spaces)
        // context.SenderClientId / context.Network: Consistent with execution stage

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

        // DisplayText: Content displayed in candidate list
        // ApplyText: Full text written back to input box when Tab is pressed
        yield return new ChatAutoCompleteItem(
            displayText: "Candidate 1",
            applyText: $"{context.Prefix}{context.CommandToken} Candidate 1"
        );

        yield return new ChatAutoCompleteItem(
            displayText: "Candidate 2",
            applyText: $"{context.Prefix}{context.CommandToken} Candidate 2"
        );
    }
}

Suggestions:

  • For ApplyText, please return the "complete input content" (including prefix and command name), so the UI doesn't need to understand your command format.
  • If there are many candidates, please sort/filter them internally within the command (e.g., prefix matching priority).

5. FAQ

5.1 Why do default player names (e.g., "Player 0") appear in candidates?

Online player names are usually synchronized asynchronously. If you are doing player name completion, it is recommended to use data sources that have "resolved to real names" and trigger requests in the background to fetch names.

5.2 Can I display richer information in candidates (e.g., "Name (ID)")?

Yes:

  • DisplayText is used for display.
  • ApplyText is used for writing back.

For example, display Alice (12), but fill in Alice when applied.