ProjectMakoto/ProjectMakoto/Commands/Configuration/LevelRewardsCommand.cs

460 lines
No EOL
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Project Makoto
// Copyright (C) 2024 Fortunevale
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
namespace ProjectMakoto.Commands.Configuration;
internal sealed class LevelRewardsCommand : BaseCommand
{
public override Task<bool> BeforeExecution(SharedCommandContext ctx) => this.CheckAdmin();
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
{
return Task.Run(async () =>
{
var CommandKey = this.t.Commands.Config.LevelRewards;
#pragma warning disable CS8321 // Local function is declared but never used
string GetCurrentConfiguration(SharedCommandContext ctx)
{
var CommandKey = ctx.Bot.LoadedTranslations.Commands.Config.LevelRewards;
var str = "";
if (ctx.DbGuild.LevelRewards.Length != 0)
{
foreach (var b in ctx.DbGuild.LevelRewards.OrderBy(x => x.Level))
{
if (!ctx.Guild.Roles.ContainsKey(b.RoleId))
{
ctx.DbGuild.LevelRewards = ctx.DbGuild.LevelRewards.Remove(x => x.RoleId.ToString(), b);
continue;
}
str += $"**{ctx.BaseCommand.GetString(CommandKey.Level)}**: `{b.Level}`\n" +
$"**{ctx.BaseCommand.GetString(CommandKey.Role)}**: <@&{b.RoleId}> (`{b.RoleId}`)\n" +
$"**{ctx.BaseCommand.GetString(CommandKey.Message)}**: `{b.Message}`\n";
str += "\n\n";
}
}
else
{
str = ctx.BaseCommand.GetString(CommandKey.NoRewardsSetup, true);
}
return str;
}
#pragma warning restore CS8321 // Local function is declared but never used
if (await ctx.DbUser.Cooldown.WaitForLight(ctx))
return;
var CurrentPage = 0;
var embed = new DiscordEmbedBuilder()
{
Description = this.GetString(CommandKey.Loading, true)
}.AsLoading(ctx, this.GetString(CommandKey.Title));
_ = await this.RespondOrEdit(embed);
embed = embed.AsAwaitingInput(ctx, this.GetString(CommandKey.Title));
var selected = "";
async Task RefreshMessage()
{
List<DiscordStringSelectComponentOption> DefinedRewards = new();
embed.Description = "";
foreach (var reward in ctx.DbGuild.LevelRewards.ToList().OrderBy(x => x.Level))
{
if (!ctx.Guild.Roles.ContainsKey(reward.RoleId))
{
ctx.DbGuild.LevelRewards = ctx.DbGuild.LevelRewards.Remove(x => x.RoleId.ToString(), reward);
continue;
}
var role = ctx.Guild.GetRole(reward.RoleId);
DefinedRewards.Add(new DiscordStringSelectComponentOption($"{this.GetString(CommandKey.Level)} {reward.Level}: @{role.Name}", role.Id.ToString(), $"{reward.Message.TruncateWithIndication(100)}", (selected == role.Id.ToString()), new DiscordComponentEmoji(role.Color.GetClosestColorEmoji(ctx.Client))));
if (selected == role.Id.ToString())
{
embed.Description = $"**{this.GetString(CommandKey.Level)}**: `{reward.Level}`\n" +
$"**{this.GetString(CommandKey.Role)}**: <@&{reward.RoleId}> (`{reward.RoleId}`)\n" +
$"**{this.GetString(CommandKey.Message)}**: `{reward.Message}`\n";
}
}
if (DefinedRewards.Count > 0)
{
if (embed.Description == "")
embed.Description = this.GetString(CommandKey.SelectPrompt, true);
}
else
{
embed.Description = this.GetString(CommandKey.NoRewardsSetup, true);
}
var PreviousPage = new DiscordButtonComponent(ButtonStyle.Primary, "PreviousPage", this.GetString(this.t.Common.PreviousPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("◀")));
var NextPage = new DiscordButtonComponent(ButtonStyle.Primary, "NextPage", this.GetString(this.t.Common.NextPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶")));
var Add = new DiscordButtonComponent(ButtonStyle.Success, "Add", this.GetString(CommandKey.AddNewButton), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("")));
var Modify = new DiscordButtonComponent(ButtonStyle.Primary, "Modify", this.GetString(CommandKey.ModifyButton), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🔄")));
var Delete = new DiscordButtonComponent(ButtonStyle.Danger, "Delete", this.GetString(CommandKey.RemoveButton), false, new DiscordComponentEmoji(DiscordEmoji.FromGuildEmote(ctx.Client, 1005430134070841395)));
var Dropdown = new DiscordStringSelectComponent(this.GetString(CommandKey.SelectDropdown), DefinedRewards.Skip(CurrentPage * 20).Take(20).ToList(), "RewardSelection");
embed = embed.AsAwaitingInput(ctx, this.GetString(CommandKey.Title));
var builder = new DiscordMessageBuilder().AddEmbed(embed);
if (DefinedRewards.Count > 0)
_ = builder.AddComponents(Dropdown);
List<DiscordComponent> Row1 = new();
List<DiscordComponent> Row2 = new();
if (DefinedRewards.Skip(CurrentPage * 20).Count() > 20)
Row1.Add(NextPage);
if (CurrentPage != 0)
Row1.Add(PreviousPage);
Row2.Add(Add);
if (selected != "")
{
Row2.Add(Modify);
Row2.Add(Delete);
}
if (Row1.Count > 0)
_ = builder.AddComponents(Row1);
_ = builder.AddComponents(Row2);
_ = builder.AddComponents(MessageComponents.GetCancelButton(ctx.DbUser, ctx.Bot));
_ = await this.RespondOrEdit(builder);
}
CancellationTokenSource cancellationTokenSource = new();
async Task SelectInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
{
_ = Task.Run(async () =>
{
if (e.Message?.Id == ctx.ResponseMessage.Id && e.User.Id == ctx.User.Id)
{
cancellationTokenSource.Cancel();
cancellationTokenSource = new();
_ = Task.Delay(120000, cancellationTokenSource.Token).ContinueWith(x =>
{
if (x.IsCompletedSuccessfully)
{
ctx.Client.ComponentInteractionCreated -= SelectInteraction;
this.ModifyToTimedOut(true);
}
});
if (e.GetCustomId() == "RewardSelection")
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
selected = e.Values.First();
await RefreshMessage();
}
else if (e.GetCustomId() == "Add")
{
ctx.Client.ComponentInteractionCreated -= SelectInteraction;
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
DiscordRole selectedRole = null;
var selectedLevel = -1;
var selectedCustomText = this.GetGuildString(CommandKey.DefaultCustomText);
while (true)
{
var SelectRole = new DiscordButtonComponent((selectedRole is null ? ButtonStyle.Primary : ButtonStyle.Secondary), Guid.NewGuid().ToString(), this.GetString(CommandKey.SelectRoleButton), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👤")));
var SelectLevel = new DiscordButtonComponent((selectedLevel is -1 ? ButtonStyle.Primary : ButtonStyle.Secondary), Guid.NewGuid().ToString(), this.GetString(CommandKey.SelectLevelButton), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✨")));
var SelectCustomText = new DiscordButtonComponent((selectedCustomText.IsNullOrWhiteSpace() ? ButtonStyle.Primary : ButtonStyle.Secondary), Guid.NewGuid().ToString(), this.GetString(CommandKey.ChangeMessageButton), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🗯")));
var Finish = new DiscordButtonComponent(ButtonStyle.Success, Guid.NewGuid().ToString(), this.GetString(this.t.Common.Submit), (selectedRole is null || selectedLevel is -1 || selectedCustomText.IsNullOrWhiteSpace()), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("✅")));
var pad = TranslationUtil.CalculatePadding(ctx.DbUser, CommandKey.Role, CommandKey.Level, CommandKey.Message);
var action_embed = new DiscordEmbedBuilder
{
Description = $"`{this.GetString(CommandKey.Role).PadRight(pad)}`: {(selectedRole is null ? this.GetString(this.t.Common.NotSelected, true) : selectedRole.Mention)}\n" +
$"`{this.GetString(CommandKey.Level).PadRight(pad)}`: {(selectedLevel is -1 ? this.GetString(this.t.Common.NotSelected, true) : selectedLevel.ToEmotes())}\n" +
$"`{this.GetString(CommandKey.Message).PadRight(pad)}`: `{selectedCustomText}`"
}.AsAwaitingInput(ctx, this.GetString(CommandKey.Title));
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(action_embed)
.AddComponents(new List<DiscordComponent> { SelectRole, SelectLevel, SelectCustomText, Finish })
.AddComponents(MessageComponents.GetCancelButton(ctx.DbUser, ctx.Bot)));
var Menu = await ctx.WaitForButtonAsync();
if (Menu.TimedOut)
{
this.ModifyToTimedOut();
return;
}
if (Menu.GetCustomId() == SelectRole.CustomId)
{
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
var RoleResult = await this.PromptRoleSelection();
if (RoleResult.TimedOut)
{
this.ModifyToTimedOut();
return;
}
else if (RoleResult.Cancelled)
{
continue;
}
else if (RoleResult.Failed)
{
if (RoleResult.Exception.GetType() == typeof(NullReferenceException))
{
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().AsError(ctx).WithDescription(this.GetString(this.t.Commands.Common.Errors.NoRoles, true)));
await Task.Delay(3000);
return;
}
throw RoleResult.Exception;
}
if (RoleResult.Result.Id == ctx.DbGuild.BumpReminder.RoleId)
{
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().AsError(ctx).WithDescription(this.GetString(CommandKey.CantUseRole, true)));
await Task.Delay(3000);
continue;
}
selectedRole = RoleResult.Result;
continue;
}
else if (Menu.GetCustomId() == SelectLevel.CustomId)
{
var modal = new DiscordInteractionModalBuilder(this.GetString(CommandKey.Title), Guid.NewGuid().ToString())
.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "level", this.GetString(CommandKey.Level), "2", 1, 3, true, (selectedLevel is -1 ? 2 : selectedLevel).ToString()));
var ModalResult = await this.PromptModalWithRetry(Menu.Result.Interaction, modal, false);
if (ModalResult.TimedOut)
{
this.ModifyToTimedOut(true);
return;
}
else if (ModalResult.Cancelled)
{
continue;
}
else if (ModalResult.Errored)
{
throw ModalResult.Exception;
}
InteractionCreateEventArgs Response = ModalResult.Result;
var rawInt = Response.Interaction.GetModalValueByCustomId("level");
uint level;
try
{
level = Convert.ToUInt32(rawInt);
if (level < 2)
throw new Exception("");
}
catch (Exception)
{
continue;
}
selectedLevel = (int)level;
continue;
}
else if (Menu.GetCustomId() == SelectCustomText.CustomId)
{
var modal = new DiscordInteractionModalBuilder(this.GetString(CommandKey.Title), Guid.NewGuid().ToString())
.AddTextComponent(new DiscordTextComponent(TextComponentStyle.Small, "message", this.GetString(CommandKey.Message), this.GetGuildString(CommandKey.DefaultCustomText), 1, 256, true, selectedCustomText));
var ModalResult = await this.PromptModalWithRetry(Menu.Result.Interaction, modal, false);
if (ModalResult.TimedOut)
{
this.ModifyToTimedOut(true);
return;
}
else if (ModalResult.Cancelled)
{
continue;
}
else if (ModalResult.Errored)
{
throw ModalResult.Exception;
}
InteractionCreateEventArgs Response = ModalResult.Result;
var newMessage = Response.Interaction.GetModalValueByCustomId("message");
if (newMessage.Length > 256)
{
action_embed.Description = this.GetString(CommandKey.MessageTooLong, true);
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(action_embed.AsError(ctx, this.GetString(CommandKey.Title))));
await Task.Delay(3000);
continue;
}
selectedCustomText = newMessage;
continue;
}
else if (Menu.GetCustomId() == Finish.CustomId)
{
if (selectedRole.Id == ctx.DbGuild.BumpReminder.RoleId)
{
_ = await this.RespondOrEdit(new DiscordEmbedBuilder().AsError(ctx).WithDescription(this.GetString(CommandKey.CantUseRole, true)));
await Task.Delay(3000);
await this.ExecuteCommand(ctx, arguments);
return;
}
ctx.DbGuild.LevelRewards = ctx.DbGuild.LevelRewards.Add(new()
{
Level = selectedLevel,
RoleId = selectedRole.Id,
Message = selectedCustomText
});
action_embed.Description = this.GetString(CommandKey.AddedNewReward, true, new TVar("Role", $"<@&{selectedRole.Id}>"), new TVar("Level", selectedLevel));
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(action_embed.AsSuccess(ctx, this.GetString(CommandKey.Title))));
await Task.Delay(5000);
await RefreshMessage();
ctx.Client.ComponentInteractionCreated += SelectInteraction;
return;
}
else if (Menu.GetCustomId() == MessageComponents.CancelButtonId)
{
_ = Menu.Result.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
await RefreshMessage();
ctx.Client.ComponentInteractionCreated += SelectInteraction;
return;
}
return;
}
}
else if (e.GetCustomId() == "Modify")
{
var modal = new DiscordInteractionModalBuilder()
.WithTitle(this.GetString(CommandKey.Title))
.WithCustomId(Guid.NewGuid().ToString())
.AddTextComponents(new DiscordTextComponent(TextComponentStyle.Small, "new_text", this.GetString(CommandKey.Message), null, 0, 256, false, ctx.DbGuild.LevelRewards.First(x => x.RoleId == Convert.ToUInt64(selected)).Message));
;
var ModalResult = await this.PromptModalWithRetry(e.Interaction, modal, false);
if (ModalResult.TimedOut)
{
this.ModifyToTimedOut(true);
return;
}
else if (ModalResult.Cancelled)
{
await RefreshMessage();
return;
}
else if (ModalResult.Errored)
{
throw ModalResult.Exception;
}
InteractionCreateEventArgs Response = ModalResult.Result;
var result = Response.Interaction.GetModalValueByCustomId("new_text");
if (result.Length > 256)
{
_ = await this.RespondOrEdit(new DiscordMessageBuilder().AddEmbed(embed.WithDescription(this.GetString(CommandKey.MessageTooLong, true)).AsError(ctx, this.GetString(CommandKey.Title))));
await Task.Delay(5000);
await this.ExecuteCommand(ctx, arguments);
return;
}
ctx.DbGuild.LevelRewards.First(x => x.RoleId == Convert.ToUInt64(selected)).Message = result;
await RefreshMessage();
}
else if (e.GetCustomId() == "Delete")
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
ctx.DbGuild.LevelRewards = ctx.DbGuild.LevelRewards.Remove(x => x.RoleId.ToString(), ctx.DbGuild.LevelRewards.First(x => x.RoleId == Convert.ToUInt64(selected)));
if (ctx.DbGuild.LevelRewards.Length == 0)
{
await this.ExecuteCommand(ctx, arguments);
return;
}
embed.Description = this.GetString(CommandKey.SelectPrompt, true);
selected = "";
await RefreshMessage();
}
else if (e.GetCustomId() == "PreviousPage")
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
CurrentPage--;
await RefreshMessage();
}
else if (e.GetCustomId() == "NextPage")
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
CurrentPage++;
await RefreshMessage();
}
else if (e.GetCustomId() == MessageComponents.CancelButtonId)
{
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
this.DeleteOrInvalidate();
return;
}
}
}).Add(ctx.Bot, ctx);
}
await RefreshMessage();
_ = Task.Delay(120000, cancellationTokenSource.Token).ContinueWith(x =>
{
if (x.IsCompletedSuccessfully)
{
ctx.Client.ComponentInteractionCreated -= SelectInteraction;
this.ModifyToTimedOut(true);
}
});
ctx.Client.ComponentInteractionCreated += SelectInteraction;
});
}
}