-
Notifications
You must be signed in to change notification settings - Fork 6
Custom Command Settings
RICS supports adding per-command custom settings using the <CustomData> section inside your <CAP_ChatInteractive.ChatCommandDef> in your mod's Commands.xml.
This lets you expose toggles, numbers, text fields, headers, and spacing directly in the Command Editor without polluting global settings or requiring code changes to the core mod.
Settings are stored in the command's CommandSettings.CustomData (as JSON) and accessed at runtime with GetCustom<T>().
Inside your command definition:
<CAP_ChatInteractive.ChatCommandDef>
<defName>MyAwesomeCommand</defName>
<commandText>myawesome</commandText>
<label>my awesome</label>
<enabled>true</enabled>
<commandClass>YourMod.YourCommandClass</commandClass>
<commandDescription>Does cool stuff!</commandDescription>
<cooldownSeconds>30</cooldownSeconds>
<useCommandCooldown>true</useCommandCooldown>
<!-- Custom per-command settings appear in the Command Editor -->
<CustomData>
<!-- Add your UI elements here (order matters) -->
</CustomData>
</CAP_ChatInteractive.ChatCommandDef>Type matching is case-insensitive. Order in <CustomData> determines display order in the Command Editor under "Command Specific Settings".
Medium font header / section title. Use for grouping. A small extra gap (~4px) is added after for descenders.
<li>
<type>HeaderLabel</type>
<label>My Section</label>
</li>You can nest multiple HeaderLabels for subsections (see Passion command).
Small/regular text label (for notes or descriptions).
<li>
<type>Label</type>
<label>Some helpful note here</label>
</li>Boolean toggle. Renders as a standard checkbox.
<li>
<type>CheckBox</type>
<name>enableCoolFeature</name>
<label>Enable Cool Feature</label>
<defaultValue>true</defaultValue>
<description>Turn this on to do the cool thing.</description>
</li>Number input. Supports optional min/max. Use <type>int</type> or <type>float</type> for typed parsing.
<li>
<type>NumericTextBox</type>
<name>myValue</name>
<label>My Number Value</label>
<defaultValue>42</defaultValue>
<min>0</min>
<max>1000</max>
<description>Some number between 0 and 1000.</description>
</li>Free text input field (fallback for unrecognized types or explicit text).
<li>
<type>LabelTextBox</type>
<name>myText</name>
<label>Custom Message</label>
<defaultValue>Hello World</defaultValue>
</li>Pure vertical spacing (great for breathing room between groups). The pixel amount comes from defaultValue.
<li>
<type>Gap</type>
<defaultValue>12</defaultValue>
</li>A clickable button inside the command's custom settings. Primarily intended for "Reset to Defaults", but can be used for any action your command understands.
- The dialog automatically resets all this command's CustomData values to the defaults declared in your XML.
- It then calls
OnCustomDataButtonClicked(buttonName, settings)on your command instance so you can perform additional reset work (clear lists, other state, etc.). -
nameis passed asbuttonNameso you can support multiple buttons on one command.
<li>
<type>Button</type>
<name>resetToDefaults</name>
<label>Reset to Defaults</label>
<description>Restores all custom settings for this command to the values defined in the mod XML.</description>
</li>C# hook (put this in the class you reference from <commandClass>):
public override void OnCustomDataButtonClicked(string buttonName, CommandSettings settings)
{
if (buttonName == "resetToDefaults")
{
// CustomData values have already been reset by the editor.
// Do extra work here if needed, e.g.:
// settings.AllowedRaidTypes.Clear();
// settings.AllowedRaidStrategies.Clear();
}
}Buttons only execute inside the in-game Command Editor (on the streamer's machine).
In your ChatCommand subclass or handler:
public override string Execute(ChatMessageWrapper messageWrapper, string[] args)
{
var settings = GetCommandSettings(); // Preferred if inside ChatCommand subclass
// Or explicitly (works from any handler or static method):
// var settings = CommandSettingsManager.GetSettings("myawesome");
bool coolFeature = settings.GetCustom<bool>("enableCoolFeature", true);
int value = settings.GetCustom<int>("myValue", 42);
string text = settings.GetCustom<string>("myText", "default");
if (!coolFeature)
return "That feature is disabled for this command.";
// ... your logic using the values ...
}-
GetCustom<T>(key, defaultValue)safely returns the stored value or your provided default. - Values are stored as strings in JSON but
GetCustomparses to bool/int/float/string. - Use
SetCustom<T>(key, value)if you need to persist changes from code (rare for modder commands; most changes come from the in-game Command Editor). - Call
settings.EnsureCustomDefaults(def.CustomData)if you need defaults populated manually (the editor and initializer normally do this for you).
-
Order matters: Elements are rendered top-to-bottom exactly as they appear in
<CustomData>. - Use
HeaderLabelfor section titles inside your custom settings. You can use multiple HeaderLabels for subsections. - Use
Gap(4–16 pixels is common) to separate groups. - Provide good
<description>text — it becomes a tooltip in the editor. - For sub-commands (e.g.
!mypawn body,!mypawn mech), useenabledcheckboxes and check them early in your handler. Return a friendly message like"Sub Command body is disabled." - Keep names consistent and descriptive (
enableX,costY,multiplierZ). - Add your CustomData after the standard fields (
cooldownSeconds,useCommandCooldown, etc.). - For simple on/off social-style interactions, a single top-level
<CheckBox name="enabled">+ early return check is sufficient (see Social Commands).
In XML (excerpt):
<CustomData>
<li><type>HeaderLabel</type><label>MyPawn Sub-Commands</label></li>
<li><type>CheckBox</type><name>enableBody</name><label>Body</label><defaultValue>true</defaultValue></li>
<li><type>CheckBox</type><name>enableHealth</name><label>Health</label><defaultValue>true</defaultValue></li>
... (gear, skills, psycasts, mechs, etc.)
</CustomData>Early check in handler (MyPawnCommandHandler.cs):
var cmdSettings = CommandSettingsManager.GetSettings("mypawn");
string settingKey = null;
switch (sub)
{
case "body": settingKey = "enableBody"; break;
case "health": settingKey = "enableHealth"; break;
// ... map other subs
case "psycasts": settingKey = "enablePsycasts"; break;
case "mechs": settingKey = "enableMechs"; break;
}
if (settingKey != null && !cmdSettings.GetCustom<bool>(settingKey, true))
{
return $"Sub Command {subCommand} is disabled.";
}Many social commands (chitchat, deeptalk, flirt, etc.) declare a tiny CustomData:
<CustomData>
<li>
<type>CheckBox</type>
<name>enabled</name>
<label>chitchat</label>
<defaultValue>true</defaultValue>
</li>
</CustomData>Check early (EnhancedInteractionCommandHandler.cs style):
var cmdSettings = CommandSettingsManager.GetSettings(cmdName); // "chitchat", "flirt", etc.
if (!cmdSettings.GetCustom<bool>("enabled", true))
{
return $"Sub Command {cmdName} is disabled.";
}Passion uses many grouped numerics + headers:
<CustomData>
<li><type>HeaderLabel</type><label>Wager Limits and Scaling</label></li>
<li><type>int</type><name>minPassionWager</name> ... </li>
...
<li><type>HeaderLabel</type><label>Success Chance Scaling</label></li>
...
</CustomData>Usage:
var s = CommandSettingsManager.GetSettings("passion");
int minW = s.GetCustom<int>("minPassionWager", 500);
float bonus = s.GetCustom<float>("passionWagerBonusPer100", 1.0f);Raid and MilitaryAid store only their three wager fields (default/min/max) via CustomData so they don't bloat the shared settings object.
<CustomData>
<li>
<type>HeaderLabel</type>
<label>Advanced Options</label>
</li>
<li>
<type>CheckBox</type>
<name>enableFeature</name>
<label>Enable Special Feature</label>
<defaultValue>true</defaultValue>
<description>Does the special thing when on.</description>
</li>
<li>
<type>Gap</type>
<defaultValue>8</defaultValue>
</li>
<li>
<type>NumericTextBox</type>
<name>bonusAmount</name>
<label>Bonus Amount</label>
<defaultValue>50</defaultValue>
<min>0</min>
<max>500</max>
</li>
</CustomData>Static handlers or other classes can fetch settings by the commandText (or defName lowercased in some cases):
var settings = CommandSettingsManager.GetSettings("myawesome");
bool feature = settings.GetCustom<bool>("enableFeature", true);Place the <CAP_ChatInteractive.ChatCommandDef> (with its <CustomData>) inside a Defs/Commands/Something.xml in your own mod.
Example folder structure:
YourMod/
About/
About.xml
Defs/
Commands/
MyCommands.xml
Your mod must load after (or be compatible with) RICS so the Def type is recognized. Use the same <commandClass> pointing to your handler code.
You can also patch existing commands from RICS to add CustomData via XML patches if desired (advanced).
- These settings only affect your command — they do not appear for other commands.
- The Command Editor will automatically show a "Command Specific Settings" section when your command has CustomData.
- Changes are saved in the user's
CommandSettings.jsonunder your command's entry. - Core RICS commands (raid, mypawn, passion, surgery, socials, etc.) already use this system extensively.
This system is designed so addon authors and custom command creators can add rich, per-command configuration without touching global settings or core RICS code.
Happy modding! If you create cool commands, consider sharing them on the RICS Discord or GitHub discussions.