Commands
SwiftlyS2 provides a comprehensive command system that allows you to register custom commands, handle player chat and commands, and manage command permissions. Commands can be registered using attributes or programmatically.
Registering Commands with Attributes
The simplest way to register commands is using the [Command] attribute.
[Command("heal")]
public void OnHealCommand(ICommandContext context)
{
if (!context.IsSentByPlayer)
{
context.Reply("This command can only be used by players!");
return;
}
var player = context.Sender!;
// code
}By default, commands are registered with the sw_ prefix, so the above command would be sw_heal.
Register Raw Commands
To register a command without the sw_ prefix, use registerRaw: true:
[Command("teleport", registerRaw: true)]
public void OnTeleportCommand(ICommandContext context)
{
// This command is registered as "teleport" instead of "sw_teleport"
context.Reply("Teleporting...");
}Commands with Permissions
You can require permissions for commands:
[Command("kick", permission: "admin.kick")]
public void OnKickCommand(ICommandContext context)
{
if (!context.IsSentByPlayer)
{
context.Reply("This command can only be used by players!");
return;
}
context.Reply("Player kicked!");
}Command Aliases
Add multiple aliases to a command using the [CommandAlias] attribute:
[Command("heal")]
[CommandAlias("hp")]
[CommandAlias("restore", registerRaw: true)]
public void OnHealCommand(ICommandContext context)
{
// Can be called with: sw_heal, sw_hp, or restore
context.Reply("Healed!");
}Command Context
The ICommandContext provides information about the command execution:
[Command("info")]
public void OnInfoCommand(ICommandContext context)
{
// Check if sent by a player
if (context.IsSentByPlayer)
{
var player = context.Sender!;
context.Reply($"You are {player.Controller.PlayerName}");
}
else
{
context.Reply("Command sent from server console");
}
// Check if silent command
if (context.IsSlient)
{
context.Reply("This is a silent command");
}
// Access command arguments
if (context.Args.Length > 0)
{
context.Reply($"First argument: {context.Args[0]}");
}
// Get command prefix
context.Reply($"Command prefix: {context.Prefix}");
}Programmatic Command Registration
You can also register commands programmatically using Core.Command:
public override void Load()
{
// Register a command
Guid commandGuid = Core.Command.RegisterCommand("mycommand", (context) =>
{
context.Reply("Command executed!");
}, registerRaw: false, permission: "");
// Register an alias
Core.Command.RegisterCommandAlias("mycommand", "mycmd");
}Unregistering Commands
// Unregister by GUID
Core.Command.UnregisterCommand(commandGuid);
// Unregister by name
Core.Command.UnregisterCommand("mycommand");Client Command Hooks
Hook into all client commands to intercept or modify behavior:
Using Attributes
[ClientCommandHookHandler]
public HookResult OnClientCommand(int playerId, string commandLine)
{
var player = Core.PlayerManager.GetPlayer(playerId);
if (commandLine.StartsWith("say"))
{
Console.WriteLine($"Player {player?.Name} is using say command");
}
// Return Continue to allow the command
return HookResult.Continue;
// Return Handled to block the command
// return HookResult.Handled;
}Programmatic Registration
public override void Load()
{
Core.Command.HookClientCommand((playerId, commandLine) =>
{
Console.WriteLine($"Player {playerId} executed: {commandLine}");
return HookResult.Continue;
});
}Client Chat Hooks
Hook into player chat messages:
Using Attributes
[ClientChatHookHandler]
public HookResult OnClientChat(int playerId, string text, bool teamonly)
{
var player = Core.PlayerManager.GetPlayer(playerId);
if (text.Contains("badword"))
{
player?.PrintToChat("Please watch your language!");
return HookResult.Stop; // Block the message
}
if (teamonly)
{
Console.WriteLine($"Team message from {player?.Name}: {text}");
}
return HookResult.Continue;
}Programmatic Registration
public override void Load()
{
Guid chatHookGuid = Core.Command.HookClientChat((playerId, text, teamonly) =>
{
Console.WriteLine($"Chat from {playerId}: {text}");
return HookResult.Continue;
});
// Unhook later if needed
Core.Command.UnhookClientChat(chatHookGuid);
}Complete Example: Admin Commands
public class AdminCommands
{
[Command("kick", permission: "admin.kick")]
[CommandAlias("remove")]
public void OnKickCommand(ICommandContext context)
{
if (!context.IsSentByPlayer)
{
context.Reply("This command must be used by a player!");
return;
}
if (context.Args.Length < 1)
{
context.Reply("Usage: !kick <player>");
return;
}
var targetName = context.Args[0];
// Find and kick player logic here
context.Reply($"Kicked player: {targetName}");
}
[Command("ban", permission: "admin.ban")]
public void OnBanCommand(ICommandContext context)
{
if (context.Args.Length < 2)
{
context.Reply("Usage: !ban <player> <reason>");
return;
}
var targetName = context.Args[0];
var reason = string.Join(" ", context.Args.Skip(1));
context.Reply($"Banned {targetName} for: {reason}");
}
[Command("god", permission: "admin.god")]
public void OnGodCommand(ICommandContext context)
{
if (!context.IsSentByPlayer)
{
context.Reply("This command can only be used by players!");
return;
}
var player = context.Sender!;
// Toggle god mode logic here
context.Reply("God mode toggled!");
}
}Complete Example: Chat Filter
[ClientChatHookHandler]
public HookResult OnChatFilter(int playerId, string text, bool teamonly)
{
var player = Core.PlayerManager.GetPlayer(playerId);
if (player == null) return HookResult.Continue;
// Block spam (messages too short)
if (text.Length < 3)
{
player.PrintToChat("Message too short!");
return HookResult.Stop;
}
// Replace bad words
string[] badWords = { "badword1", "badword2" };
foreach (var badWord in badWords)
{
if (text.Contains(badWord, StringComparison.OrdinalIgnoreCase))
{
player.PrintToChat("Please watch your language!");
return HookResult.Stop;
}
}
// Log all chat
Console.WriteLine($"[{(teamonly ? "TEAM" : "ALL")}] {player.Controller.PlayerName}: {text}");
return HookResult.Continue;
}Attribute Reference
[Command] Attribute
Registers a method as a command handler.
Parameters:
name(string): The command nameregisterRaw(bool, optional): If false, addssw_prefix. Default: falsepermission(string, optional): Required permission. Default: ""
[CommandAlias] Attribute
Adds an alias to a command. Can be used multiple times.
Parameters:
alias(string): The alias nameregisterRaw(bool, optional): If false, addssw_prefix. Default: false
[ClientCommandHookHandler] Attribute
Marks a method as a client command hook handler.
Method signature:
HookResult MethodName(int playerId, string commandLine)[ClientChatHookHandler] Attribute
Marks a method as a client chat hook handler.
Method signature:
HookResult MethodName(int playerId, string text, bool teamonly)Reference
See ICommandService and ICommandContext for more details.