Commands
Namespace:
DeadworksManaged.Api
A command runs a method in your plugin when someone types its name in chat or the console.
Add a command
Put [Command] on a method.
public class MyPlugin : DeadworksPluginBase
{
public override string Name => "My Plugin";
[Command("hello", Description = "Say hello")]
public void CmdHello(Caller caller)
{
caller.Reply($"Hello, {caller.Name}!");
}
}
That gives you three ways to run it:
/helloin chat. Other players don't see the typed message.!helloin chat. Other players see the typed message.dw_helloin the console.
Description is the help text shown by dw_help.
Reply to whoever ran it
Make Caller the first parameter. It is whoever ran the command: a player, or the server console.
caller.Reply("Done.");
A player sees the reply in chat. The server console sees it in the console.
Get the player who ran it
[Command("heal")]
public void CmdHeal(Caller caller)
{
var pawn = caller.Player?.GetHeroPawn();
if (pawn == null)
throw new CommandException("Only players can heal.");
pawn.Heal(pawn.GetMaxHealth());
}
caller.Player is null when the server console ran the command. See Players for what you can do with one.
Refuse with a message
Throw CommandException. The caller sees your message wherever they typed the command. The rest of your method doesn't run.
throw new CommandException("You can't do that right now.");
Any other exception is a bug in your plugin. The server console gets the full stack trace. The caller sees only That command failed. The server console has details.
Take arguments
Add more parameters. Deadworks fills them in from what the caller typed.
[Command("givesouls", Description = "Give yourself souls")]
public void CmdGiveSouls(Caller caller, int amount = 50000)
{
// ...
}
/givesouls
/givesouls 2500
A parameter can be a string, a bool, a number (int, long, uint, ulong, float, double) or an enum, or a nullable version of one. One with a default value is optional. An enum takes its value names (red, blue), not numbers.
If what they typed doesn't fit, Deadworks shows them the usage and doesn't run your method:
Usage: dw_givesouls [amount=50000]
Pick players
Take a Target to let the caller name one or more players:
[Command("healplayer", Permission = "myplugin.heal")]
public void CmdHealPlayer(Caller caller, Target target)
{
foreach (var player in target)
{
var pawn = player.GetHeroPawn();
pawn?.Heal(pawn.GetMaxHealth());
}
}
/healplayer lapka
/healplayer #3
/healplayer @team
A Target accepts part of a name, #slot, a SteamID, @me, @team, @enemy and @all. If nothing matches, Deadworks tells the caller and doesn't run your method. Use target.Single() when the command only makes sense for one player. See Target.
Parse your own types
For a type Deadworks doesn't parse, register a converter in OnLoad. Throw CommandException to tell the caller what's wrong with what they typed:
public override void OnLoad(bool isReload)
{
CommandConverters.Register<Coord>(text =>
text.Split(',') is [var x, var y] && int.TryParse(x, out var xi) && int.TryParse(y, out var yi)
? new Coord(xi, yi)
: throw new CommandException($"'{text}' isn't x,y."));
}
Your converters are removed when your plugin unloads. A converter applies to every plugin's commands, so register them for your own types. Registering one for a type Deadworks already parses, such as int or Target, throws ArgumentException.
If a parameter's type can't be parsed at all, the server console warns when the plugin loads, and the command only ever shows its usage.
Take a whole sentence
Make the last parameter params string[] to collect everything else the caller typed.
[Command("sayas")]
public void CmdSayAs(Caller caller, string speaker, params string[] messageParts)
{
var text = string.Join(' ', messageParts);
}
/sayas announcer the match starts now
Give a command a second name
Add more names after the first.
[Command("heal", "h")]
Now /h, !h and dw_h work too.
Make a command chat only or console only
[Command("hello", ChatOnly = true)] // only /hello and !hello
[Command("hello", ConsoleOnly = true)] // only dw_hello
Players can still run a ConsoleOnly command from their own game console. To keep a command to the server console, use ServerOnly instead.
Only let the server console run a command
[Command("cvardump", ServerOnly = true)]
To limit a command to certain players instead, see Permissions.
Hide a command
[Command("secret", Hidden = true)] // left out of dw_help
[Command("secret", SuppressChat = true)] // typing !secret isn't shown in chat
Wait for something slow
A command can be async if it returns Task. Code after an await continues on the game thread, so it can touch the game as usual.
[Command("stats")]
public async Task CmdStats(Caller caller)
{
var stats = await _database.LoadStatsAsync(caller.SteamId64);
caller.Reply($"You've played {stats.Matches} matches.");
}
If the player has left by then, the reply does nothing. An exception thrown after an await is handled the same way as one thrown straight away.
async voidAn exception in an async void method can't be caught and would crash the server. Deadworks refuses to register such a command and says so in the server console. Return Task instead.
See also
- Permissions: limit who can run a command
- Players: what you can do with a player
- Console commands: built-in
dw_commands