mirror of https://github.com/oliverbooth/VPLink
feat: replace !who with /who slash command
This commit is contained in:
parent
a1086a834c
commit
bb03b68c17
|
@ -0,0 +1,73 @@
|
|||
using Cysharp.Text;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using VpSharp;
|
||||
using VpSharp.Entities;
|
||||
|
||||
namespace VpBridge.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a class which implements the <c>who</c> command.
|
||||
/// </summary>
|
||||
internal sealed class WhoCommand : InteractionModuleBase<SocketInteractionContext>
|
||||
{
|
||||
private readonly VirtualParadiseClient _virtualParadiseClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WhoCommand" /> class.
|
||||
/// </summary>
|
||||
/// <param name="virtualParadiseClient">The Virtual Paradise client.</param>
|
||||
public WhoCommand(VirtualParadiseClient virtualParadiseClient)
|
||||
{
|
||||
_virtualParadiseClient = virtualParadiseClient;
|
||||
}
|
||||
|
||||
[SlashCommand("who", "Displays a list of active users in Virtual Paradise.")]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task HandleAsync()
|
||||
{
|
||||
var embed = new EmbedBuilder();
|
||||
embed.WithColor(0x1E88E5);
|
||||
embed.WithAuthor($"🌎 {_virtualParadiseClient.CurrentWorld?.Name}");
|
||||
embed.WithTitle("Active Users");
|
||||
embed.WithTimestamp(DateTimeOffset.UtcNow);
|
||||
|
||||
using Utf8ValueStringBuilder userBuilder = ZString.CreateUtf8StringBuilder();
|
||||
using Utf8ValueStringBuilder botsBuilder = ZString.CreateUtf8StringBuilder();
|
||||
var userCount = 0;
|
||||
var botCount = 0;
|
||||
|
||||
foreach (VirtualParadiseAvatar avatar in _virtualParadiseClient.Avatars)
|
||||
{
|
||||
if (avatar.IsBot)
|
||||
{
|
||||
botsBuilder.AppendLine($"* {avatar.Name} ({avatar.Session})");
|
||||
botCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
userBuilder.AppendLine($"* {avatar.Name} ({avatar.Session})");
|
||||
userCount++;
|
||||
}
|
||||
}
|
||||
|
||||
string userTitle = userCount switch
|
||||
{
|
||||
0 => "Users",
|
||||
1 => "1 User",
|
||||
_ => $"{userCount} Users"
|
||||
};
|
||||
|
||||
string botTitle = botCount switch
|
||||
{
|
||||
0 => "Bots",
|
||||
1 => "1 Bot",
|
||||
_ => $"{botCount} Bots"
|
||||
};
|
||||
|
||||
embed.AddField($"👤 {userTitle}", userCount > 0 ? userBuilder.ToString() : "*None*", true);
|
||||
embed.AddField($"🤖 {botTitle}", botCount > 0 ? botsBuilder.ToString() : "*None*", true);
|
||||
|
||||
await RespondAsync(embed: embed.Build());
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Discord;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
@ -24,10 +25,13 @@ builder.Logging.ClearProviders();
|
|||
builder.Logging.AddSerilog();
|
||||
|
||||
builder.Services.AddSingleton<VirtualParadiseClient>();
|
||||
builder.Services.AddSingleton(new DiscordSocketClient(new DiscordSocketConfig
|
||||
|
||||
builder.Services.AddSingleton<InteractionService>();
|
||||
builder.Services.AddSingleton<DiscordSocketClient>();
|
||||
builder.Services.AddSingleton(new DiscordSocketConfig
|
||||
{
|
||||
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent
|
||||
}));
|
||||
});
|
||||
|
||||
builder.Services.AddHostedSingleton<IVirtualParadiseService, VirtualParadiseService>();
|
||||
builder.Services.AddHostedSingleton<IDiscordService, DiscordService>();
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
using System.Reactive.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using VpBridge.Commands;
|
||||
using VpSharp;
|
||||
using VpSharp.Entities;
|
||||
|
||||
|
@ -19,7 +21,9 @@ internal sealed partial class DiscordService : BackgroundService, IDiscordServic
|
|||
private static readonly Regex EscapeRegex = GetEscapeRegex();
|
||||
|
||||
private readonly ILogger<DiscordService> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly InteractionService _interactionService;
|
||||
private readonly DiscordSocketClient _discordClient;
|
||||
private readonly VirtualParadiseClient _virtualParadiseClient;
|
||||
private readonly Subject<IUserMessage> _messageReceived = new();
|
||||
|
@ -28,16 +32,22 @@ internal sealed partial class DiscordService : BackgroundService, IDiscordServic
|
|||
/// Initializes a new instance of the <see cref="DiscordService" /> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="serviceProvider">The service provider.</param>
|
||||
/// <param name="configuration">The configuration.</param>
|
||||
/// <param name="interactionService">The interaction service.</param>
|
||||
/// <param name="discordClient">The Discord client.</param>
|
||||
/// <param name="virtualParadiseClient">The Virtual Paradise client.</param>
|
||||
public DiscordService(ILogger<DiscordService> logger,
|
||||
IServiceProvider serviceProvider,
|
||||
IConfiguration configuration,
|
||||
InteractionService interactionService,
|
||||
DiscordSocketClient discordClient,
|
||||
VirtualParadiseClient virtualParadiseClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
_configuration = configuration;
|
||||
_interactionService = interactionService;
|
||||
_discordClient = discordClient;
|
||||
_virtualParadiseClient = virtualParadiseClient;
|
||||
}
|
||||
|
@ -49,40 +59,13 @@ internal sealed partial class DiscordService : BackgroundService, IDiscordServic
|
|||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("Establishing relay");
|
||||
_discordClient.MessageReceived += arg =>
|
||||
{
|
||||
if (arg is not IUserMessage message)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (message.Channel.Id != _configuration.GetSection("Discord:ChannelId").Get<ulong>())
|
||||
return Task.CompletedTask;
|
||||
_logger.LogInformation("Adding command modules");
|
||||
await _interactionService.AddModuleAsync<WhoCommand>(_serviceProvider).ConfigureAwait(false);
|
||||
|
||||
if (message.Content.Equals("!who"))
|
||||
{
|
||||
VirtualParadiseAvatar[] avatars = _virtualParadiseClient.Avatars.Where(a => !a.IsBot).ToArray();
|
||||
int count = avatars.Length;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
builder.AppendLine("**Users In World 🌎**");
|
||||
foreach (VirtualParadiseAvatar avatar in _virtualParadiseClient.Avatars)
|
||||
{
|
||||
if (avatar.IsBot || avatar == _virtualParadiseClient.CurrentAvatar)
|
||||
continue;
|
||||
|
||||
builder.AppendLine($"• {avatar.Name}");
|
||||
}
|
||||
|
||||
return message.ReplyAsync(builder.ToString());
|
||||
}
|
||||
|
||||
return message.ReplyAsync("**No Users In World 🚫**");
|
||||
}
|
||||
|
||||
_messageReceived.OnNext(message);
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
_discordClient.Ready += OnReady;
|
||||
_discordClient.InteractionCreated += OnInteractionCreated;
|
||||
_discordClient.MessageReceived += OnDiscordMessageReceived;
|
||||
|
||||
string token = _configuration.GetSection("Discord:Token").Value ??
|
||||
throw new InvalidOperationException("Token is not set.");
|
||||
|
@ -92,6 +75,45 @@ internal sealed partial class DiscordService : BackgroundService, IDiscordServic
|
|||
await _discordClient.StartAsync();
|
||||
}
|
||||
|
||||
private Task OnDiscordMessageReceived(SocketMessage arg)
|
||||
{
|
||||
if (arg is not IUserMessage message)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (message.Channel.Id != _configuration.GetSection("Discord:ChannelId").Get<ulong>())
|
||||
return Task.CompletedTask;
|
||||
|
||||
_messageReceived.OnNext(message);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task OnInteractionCreated(SocketInteraction interaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new SocketInteractionContext(_discordClient, interaction);
|
||||
IResult result = await _interactionService.ExecuteCommandAsync(context, _serviceProvider);
|
||||
|
||||
if (!result.IsSuccess)
|
||||
switch (result.Error)
|
||||
{
|
||||
case InteractionCommandError.UnmetPrecondition:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (interaction.Type is InteractionType.ApplicationCommand)
|
||||
await interaction.GetOriginalResponseAsync().ContinueWith(async msg => await msg.Result.DeleteAsync());
|
||||
}
|
||||
}
|
||||
|
||||
private Task OnReady()
|
||||
{
|
||||
_logger.LogInformation("Discord client ready");
|
||||
return _interactionService.RegisterCommandsGloballyAsync();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SendMessageAsync(VirtualParadiseMessage message)
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<PackageReference Include="VpSharp" Version="0.1.0-nightly.43"/>
|
||||
<PackageReference Include="X10D" Version="3.3.1"/>
|
||||
<PackageReference Include="X10D.Hosting" Version="3.3.1"/>
|
||||
<PackageReference Include="ZString" Version="2.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue