diff --git a/DiscordLab.Bot/API/Modules/UpdateStatus.cs b/DiscordLab.Bot/API/Modules/UpdateStatus.cs index 4fa6b34..655992b 100644 --- a/DiscordLab.Bot/API/Modules/UpdateStatus.cs +++ b/DiscordLab.Bot/API/Modules/UpdateStatus.cs @@ -35,6 +35,8 @@ public static class UpdateStatus private static readonly HttpClient Client = new (); private static readonly string Path = Paths.Plugins; + + public static List Statuses { get; private set; } /// /// This will write a plugin to the Plugins folder. @@ -46,6 +48,16 @@ private static void WritePlugin(byte[] bytes, string name) string pluginPath = System.IO.Path.Combine(Path, name + ".dll"); File.WriteAllBytes(pluginPath, bytes); } + + /// + /// This will download a plugin using + /// + /// The + public static async Task DownloadPlugin(API.Features.UpdateStatus status) + { + byte[] pluginData = await Client.GetByteArrayAsync(status.Url); + WritePlugin(pluginData, status.ModuleName); + } /// /// This will check the GitHub API for the latest version of the modules and plugins. @@ -81,6 +93,8 @@ public static async Task GetStatus() } } } + + Statuses = statuses; List> plugins = Loader.Plugins.Where(x => x.Name.StartsWith("DiscordLab.")).ToList(); plugins.Add(Loader.Plugins.First(x => x.Name == Plugin.Instance.Name)); @@ -98,8 +112,7 @@ public static async Task GetStatus() if (Plugin.Instance.Config.AutoUpdate) { pluginsToUpdate.Add(status.ModuleName); - byte[] pluginData = await Client.GetByteArrayAsync(status.Url); - WritePlugin(pluginData, status.ModuleName); + await DownloadPlugin(status); } else { diff --git a/DiscordLab.Bot/Commands/Discord.cs b/DiscordLab.Bot/Commands/Discord.cs new file mode 100644 index 0000000..8b0c80c --- /dev/null +++ b/DiscordLab.Bot/Commands/Discord.cs @@ -0,0 +1,74 @@ +using Discord; +using Discord.WebSocket; +using DiscordLab.Bot.API.Interfaces; +using DiscordLab.Bot.API.Modules; + +namespace DiscordLab.Bot.Commands +{ + public class Discord : ISlashCommand + { + public SlashCommandBuilder Data { get; } = new() + { + Name = "discordlab", + Description = "DiscordLab related commands", + DefaultMemberPermissions = GuildPermission.Administrator, + Options = new() + { + new() + { + Type = ApplicationCommandOptionType.SubCommand, + Name = "list", + Description = "List all available DiscordLab modules", + }, + new() + { + Type = ApplicationCommandOptionType.SubCommand, + Name = "install", + Description = "Install a DiscordLab module", + Options = new () + { + new () + { + Type = ApplicationCommandOptionType.String, + Name = "module", + Description = "The module to install", + IsRequired = true, + IsAutocomplete = true + } + } + } + } + }; + + public ulong GuildId { get; set; } = Plugin.Instance.Config.GuildId; + + public async Task Run(SocketSlashCommand command) + { + string subcommand = command.Data.Options.First().Name; + if (subcommand == "list") + { + string modules = string.Join("\n", UpdateStatus.Statuses.Where(s => s.ModuleName != "DiscordLab.Bot").Select(s => s.ModuleName)); + await command.RespondAsync("List of available DiscordLab modules:\n\n" + modules, ephemeral:true); + } + else if (subcommand == "install") + { + string module = command.Data.Options.First().Options.First().Value.ToString(); + if(string.IsNullOrWhiteSpace(module)) + { + await command.RespondAsync("Please provide a module name.", ephemeral: true); + return; + } + API.Features.UpdateStatus status = UpdateStatus.Statuses.FirstOrDefault(s => s.ModuleName == module); + if (status == null) + { + await command.RespondAsync("Module not found.", ephemeral: true); + return; + } + + await UpdateStatus.DownloadPlugin(status); + ServerStatic.StopNextRound = ServerStatic.NextRoundAction.Restart; + await command.RespondAsync("Downloaded module. Server will restart next round.", ephemeral:true); + } + } + } +} \ No newline at end of file diff --git a/DiscordLab.Bot/Commands/LocalAdmin.cs b/DiscordLab.Bot/Commands/LocalAdmin.cs new file mode 100644 index 0000000..ba77267 --- /dev/null +++ b/DiscordLab.Bot/Commands/LocalAdmin.cs @@ -0,0 +1,53 @@ +using CommandSystem; +using DiscordLab.Bot.API.Modules; +using PluginAPI.Core; + +namespace DiscordLab.Bot.Commands +{ + [CommandHandler(typeof(GameConsoleCommandHandler))] + public class LocalAdmin : ICommand + { + public string Command { get; } = "discordlab"; + + public string[] Aliases { get; } = new [] { "dl", "lab" }; + + public string Description { get; } = "Do things directly with DiscordLab."; + + public bool Execute( + ArraySegment arguments, + ICommandSender sender, + out string response + ) + { + switch (arguments.FirstOrDefault()) + { + case "list": + string modules = string.Join("\n", UpdateStatus.Statuses.Where(s => s.ModuleName != "DiscordLab.Bot").Select(s => s.ModuleName)); + response = + $"Available modules:\n{modules}"; + return true; + case "install": + string module = arguments.ElementAtOrDefault(1); + if(string.IsNullOrWhiteSpace(module)) + { + response = "Please provide a module name."; + return false; + } + API.Features.UpdateStatus status = UpdateStatus.Statuses.FirstOrDefault(s => s.ModuleName == module); + if (status == null) + { + response = "Module not found."; + return false; + } + + Task.Run(async () => await UpdateStatus.DownloadPlugin(status)); + ServerStatic.StopNextRound = ServerStatic.NextRoundAction.Restart; + response = "Downloaded module. Server will restart next round."; + return true; + default: + response = "Invalid subcommand. Available subcommands: list, install"; + return false; + } + } + } +} \ No newline at end of file diff --git a/DiscordLab.Bot/Handlers/DiscordBot.cs b/DiscordLab.Bot/Handlers/DiscordBot.cs index c9e1305..8227cbc 100644 --- a/DiscordLab.Bot/Handlers/DiscordBot.cs +++ b/DiscordLab.Bot/Handlers/DiscordBot.cs @@ -26,6 +26,7 @@ public void Init() Client.Log += DiscLog; Client.Ready += Ready; Client.SlashCommandExecuted += SlashCommandHandler; + Client.AutocompleteExecuted += AutoCompleteHandler; Task.Run(StartClient); } @@ -84,5 +85,21 @@ private async Task SlashCommandHandler(SocketSlashCommand command) if (cmd == null) return; await cmd.Run(command); } + + private async Task AutoCompleteHandler(SocketAutocompleteInteraction autocomplete) + { + List commands = SlashCommandLoader.Commands; + ISlashCommand cmd = commands.FirstOrDefault(c => c.Data.Name == autocomplete.Data.CommandName); + if (cmd == null) return; + if (cmd.Data.Name == "discordlab") + { + await autocomplete.RespondAsync(result: UpdateStatus.Statuses + .Where(s => s.ModuleName != "DiscordLab.Bot").Select(s => new AutocompleteResult + { + Name = s.ModuleName, + Value = s.ModuleName + })); + } + } } } \ No newline at end of file