8.4 KiB
Command Arguments
Now that we have basic commands working, lets make them actually useful by adding arguments. Arguments are the extra words a user types after a command, for example:
say Hello World → the bot should reply with Hello World
repeat 3 Hey → the bot should reply with Hey Hey Hey
How arguments work
After we strip the prefix from the message content, we can split the remaining text into an array of words. The first word is the command name, and everything after is the arguments.
// Strip the prefix from the content
string withoutPrefix = content.Substring(prefix.Length);
// Split into parts: parts[0] = command name, parts[1..] = arguments
string[] parts = withoutPrefix.Split(' ', StringSplitOptions.RemoveEmptyEntries);
// The command name is the first part (lowercase so Ping and ping both work)
string command = parts[0].ToLower();
// The arguments are everything after the command name
string[] args = parts.Skip(1).ToArray();
Adding a say command
The say command takes all the arguments and echoes them back as a message. We join the args array back into a single string using string.Join.
if (command == "say")
{
// Make sure the user actually gave us something to say
if (args.Length == 0)
{
await channel.SendMessageAsync("Usage: bg/say <message>");
return;
}
// Join all the arguments back into one string and send it
string messageToSay = string.Join(' ', args);
await channel.SendMessageAsync(messageToSay);
}
Adding a repeat command
The repeat command takes a number and a word, then repeats the word that many times. This shows how to parse an argument as a specific type (int).
else if (command == "repeat")
{
// Make sure the user gave us a number AND a word
if (args.Length < 2)
{
await channel.SendMessageAsync("Usage: bg/repeat <number> <word>");
return;
}
// Try to parse the first argument as a number
if (!int.TryParse(args[0], out int times))
{
await channel.SendMessageAsync("The first argument must be a number!");
return;
}
// Clamp the number so people can't repeat 10000 times
times = Math.Clamp(times, 1, 10);
// Repeat the word and send the result
string word = args[1];
string result = string.Join(' ', Enumerable.Repeat(word, times));
await channel.SendMessageAsync(result);
}
Updating onMessageReceived
Now we replace the old if check with the new argument-aware approach inside onMessageReceived:
// Function for what to do with the received messages
async Task onMessageReceived(Message message)
{
// Prefix.. duh..
string prefix = "bg/";
// What the message says
string content = message.Content;
// Get the channel that the message was sent in
if (!channelCache.TryGetValue(message.ChannelId, out var channel)) return;
// If the message doesnt start with the prefix then just ignore it
if (!content.StartsWith(prefix)) return;
// Strip the prefix and split the rest into parts
// parts[0] = command name, parts[1..] = arguments
string withoutPrefix = content.Substring(prefix.Length);
string[] parts = withoutPrefix.Split(' ', StringSplitOptions.RemoveEmptyEntries);
// If there's nothing after the prefix, ignore it
if (parts.Length == 0) return;
// Grab the command name (lowercase so Ping and ping both work)
string command = parts[0].ToLower();
// Grab any arguments that come after the command name
string[] args = parts.Skip(1).ToArray();
// Check if the command is ping
if (command == "ping")
{
// Sends the message `Pong!` to the channel
await channel.SendMessageAsync("Pong!");
}
// Check if the command is say
else if (command == "say")
{
// Make sure the user actually gave us something to say
if (args.Length == 0)
{
await channel.SendMessageAsync("Usage: bg/say <message>");
return;
}
// Join all the arguments back into one string and send it
string messageToSay = string.Join(' ', args);
await channel.SendMessageAsync(messageToSay);
}
// Check if the command is repeat
else if (command == "repeat")
{
// Make sure the user gave us a number AND a word
if (args.Length < 2)
{
await channel.SendMessageAsync("Usage: bg/repeat <number> <word>");
return;
}
// Try to parse the first argument as a number
if (!int.TryParse(args[0], out int times))
{
await channel.SendMessageAsync("The first argument must be a number!");
return;
}
// Clamp the number so people can't repeat 10000 times
times = Math.Clamp(times, 1, 10);
// Repeat the word and send the result
string word = args[1];
string result = string.Join(' ', Enumerable.Repeat(word, times));
await channel.SendMessageAsync(result);
}
}
Full code below
using Valour.Sdk.Client;
using Valour.Shared;
using DotNetEnv;
using Valour.Sdk.Models;
using Valour.Shared.Models;
ValourClient client = new ValourClient("https://api.valour.gg/");
client.SetupHttpClient();
Env.Load();
string token = Environment.GetEnvironmentVariable("TOKEN") ?? string.Empty;
Dictionary<long, Channel> channelCache = new();
if (string.IsNullOrWhiteSpace(token))
{
Console.WriteLine($"Token invalid. Please make sure you set a valid token in your .env");
return;
}
TaskResult loginResult = await client.InitializeUser(token);
if (!loginResult.Success)
{
Console.WriteLine($"Login failed: {loginResult.Message}");
}
Console.WriteLine($"Logged in as {client.Me.Name} (ID: {client.Me.Id})");
foreach (Planet planet in client.PlanetService.JoinedPlanets)
{
await planet.EnsureReadyAsync();
await planet.FetchInitialDataAsync();
foreach (Channel chan in planet.Channels)
{
channelCache[chan.Id] = chan;
if (chan.ChannelType == ChannelTypeEnum.PlanetChat)
{
await chan.OpenWithResult("YourBotName");
}
}
}
client.MessageService.MessageReceived += onMessageReceived;
async Task onMessageReceived(Message message)
{
string prefix = "bg/";
string content = message.Content;
if (!channelCache.TryGetValue(message.ChannelId, out var channel)) return;
if (!content.StartsWith(prefix)) return;
// Strip the prefix and split the rest into parts
// parts[0] = command name, parts[1..] = arguments
string withoutPrefix = content.Substring(prefix.Length);
string[] parts = withoutPrefix.Split(' ', StringSplitOptions.RemoveEmptyEntries);
// If there's nothing after the prefix, ignore it
if (parts.Length == 0) return;
// Grab the command name (lowercase so Ping and ping both work)
string command = parts[0].ToLower();
// Grab any arguments that come after the command name
string[] args = parts.Skip(1).ToArray();
if (command == "ping")
{
await channel.SendMessageAsync("Pong!");
}
// Check if the command is say
else if (command == "say")
{
// Make sure the user actually gave us something to say
if (args.Length == 0)
{
await channel.SendMessageAsync($"Usage: {prefix}say <message>");
return;
}
// Join all the arguments back into one string and send it
string messageToSay = string.Join(' ', args);
await channel.SendMessageAsync(messageToSay);
}
// Check if the command is repeat
else if (command == "repeat")
{
// Make sure the user gave us a number AND a word
if (args.Length < 2)
{
await channel.SendMessageAsync($"Usage: {prefix}repeat <number> <word>");
return;
}
// Try to parse the first argument as a number
if (!int.TryParse(args[0], out int times))
{
await channel.SendMessageAsync("The first argument must be a number!");
return;
}
// Clamp the number so people can't repeat 10000 times
times = Math.Clamp(times, 1, 10);
// Repeat the word and send the result
string word = args[1];
string result = string.Join(' ', Enumerable.Repeat(word, times));
await channel.SendMessageAsync(result);
}
}
await Task.Delay(Timeout.Infinite);