Initial commit
This commit is contained in:
commit
b0318f5602
26 changed files with 3247 additions and 0 deletions
365
Commands/ScoreSaberCommandAbstractions.cs
Normal file
365
Commands/ScoreSaberCommandAbstractions.cs
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
// 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
|
||||
|
||||
using System.Globalization;
|
||||
using ProjectMakoto.Entities.ScoreSaber;
|
||||
using ProjectMakoto.Enums.ScoreSaber;
|
||||
using ProjectMakoto.Exceptions;
|
||||
using ProjectMakoto.Plugins.ScoreSaber;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal static class ScoreSaberCommandAbstractions
|
||||
{
|
||||
internal static async Task SendScoreSaberProfile(SharedCommandContext ctx, BaseCommand cmd, string id = "", bool AddLinkButton = true)
|
||||
{
|
||||
var CommandKey = ((Plugins.ScoreSaber.Entities.Translations)ScoreSaberPlugin.Plugin!.Translations).Commands.ScoreSaber;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
if (ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId != 0)
|
||||
{
|
||||
id = ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.BaseCommand.SendSyntaxError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = cmd.GetString(CommandKey.Profile.LoadingPlayer, true)
|
||||
}.AsLoading(ctx, "Score Saber");
|
||||
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
|
||||
try
|
||||
{
|
||||
var player = await ScoreSaberPlugin.ScoreSaber!.GetPlayerById(id);
|
||||
|
||||
CancellationTokenSource cancellationTokenSource = new();
|
||||
|
||||
DiscordButtonComponent ShowProfileButton = new(ButtonStyle.Primary, "getmain", cmd.GetString(CommandKey.Profile.ShowProfile), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("👤")));
|
||||
DiscordButtonComponent TopScoresButton = new(ButtonStyle.Primary, "gettopscores", cmd.GetString(CommandKey.Profile.ShowTopScores), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🎇")));
|
||||
DiscordButtonComponent RecentScoresButton = new(ButtonStyle.Primary, "getrecentscores", cmd.GetString(CommandKey.Profile.ShowRecentScores), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🕒")));
|
||||
|
||||
DiscordButtonComponent LinkButton = new(ButtonStyle.Primary, "thats_me", cmd.GetString(CommandKey.Profile.LinkProfileToAccount), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("↘")));
|
||||
|
||||
DiscordLinkButtonComponent OpenProfileInBrowser = new($"https://scoresaber.com/u/{id}", cmd.GetString(CommandKey.Profile.OpenInBrowser), false);
|
||||
|
||||
List<DiscordComponent> ProfileInteractionRow = new()
|
||||
{
|
||||
OpenProfileInBrowser,
|
||||
TopScoresButton,
|
||||
RecentScoresButton
|
||||
};
|
||||
|
||||
List<DiscordComponent> RecentScoreInteractionRow = new()
|
||||
{
|
||||
OpenProfileInBrowser,
|
||||
ShowProfileButton,
|
||||
TopScoresButton
|
||||
};
|
||||
|
||||
List<DiscordComponent> TopScoreInteractionRow = new()
|
||||
{
|
||||
OpenProfileInBrowser,
|
||||
ShowProfileButton,
|
||||
RecentScoresButton
|
||||
};
|
||||
|
||||
PlayerScores? CachedTopScores = null;
|
||||
PlayerScores? CachedRecentScores = null;
|
||||
|
||||
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (e.Message?.Id == ctx.ResponseMessage.Id && e.User.Id == ctx.User.Id)
|
||||
{
|
||||
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
if (e.GetCustomId() == "thats_me")
|
||||
{
|
||||
AddLinkButton = false;
|
||||
_ = ShowProfile().Add(ctx.Bot, ctx);
|
||||
ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId = Convert.ToUInt64(player.id);
|
||||
|
||||
var new_msg = await cmd.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = cmd.GetString(CommandKey.Profile.LinkSuccessful).Build(true,
|
||||
new TVar("ProfileName", player.name),
|
||||
new TVar("ProfileId", player.id),
|
||||
new TVar("ProfileCommand", $"{ctx.Prefix}scoresaber profile"),
|
||||
new TVar("UnlinkCommand", $"{ctx.Prefix}scoresaber unlink"))
|
||||
}.AsSuccess(ctx, "Score Saber")));
|
||||
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
else if (e.GetCustomId() == "gettopscores")
|
||||
{
|
||||
try
|
||||
{
|
||||
CachedTopScores ??= await ScoreSaberPlugin.ScoreSaber!.GetScoresById(id, ScoreType.Top);
|
||||
|
||||
_ = ShowScores(CachedTopScores, ScoreType.Top).Add(ctx.Bot, ctx);
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
embed = embed.AsError(ctx, "Score Saber");
|
||||
embed.Description = cmd.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
|
||||
return;
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
embed = embed.AsError(ctx, "Score Saber");
|
||||
embed.Description = cmd.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (e.GetCustomId() == "getrecentscores")
|
||||
{
|
||||
try
|
||||
{
|
||||
CachedRecentScores ??= await ScoreSaberPlugin.ScoreSaber!.GetScoresById(id, ScoreType.Recent);
|
||||
|
||||
_ = ShowScores(CachedRecentScores, ScoreType.Recent).Add(ctx.Bot, ctx);
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
embed = embed.AsError(ctx, "Score Saber");
|
||||
embed.Description = cmd.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
return;
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
cancellationTokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
embed = embed.AsError(ctx, "Score Saber");
|
||||
embed.Description = cmd.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (e.GetCustomId() == "getmain")
|
||||
{
|
||||
_ = ShowProfile().Add(ctx.Bot, ctx);
|
||||
}
|
||||
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new();
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(120000, cancellationTokenSource.Token);
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
ctx.BaseCommand.ModifyToTimedOut(true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
|
||||
async Task ShowScores(PlayerScores scores, ScoreType scoreType)
|
||||
{
|
||||
_ = embed.ClearFields();
|
||||
embed.ImageUrl = "";
|
||||
|
||||
if (!player.inactive)
|
||||
embed.Description = $":globe_with_meridians: **#{player.rank}** | :flag_{player.country.ToLower()}: **#{player.countryRank}**\n\n" +
|
||||
$"{(scoreType == ScoreType.Top ? $"**{cmd.GetString(CommandKey.Profile.TopScores)}**" : $"**{cmd.GetString(CommandKey.Profile.RecentScores)}**")}";
|
||||
else
|
||||
embed.Description = $"{cmd.GetString(CommandKey.Profile.InactiveUser, true)}\n\n" +
|
||||
$"{(scoreType == ScoreType.Top ? $"**{cmd.GetString(CommandKey.Profile.TopScores)}**" : $"**{cmd.GetString(CommandKey.Profile.RecentScores)}**")}";
|
||||
|
||||
foreach (var score in scores.playerScores.Take(5))
|
||||
{
|
||||
var page = Math.Ceiling((decimal)score.score.rank / (decimal)12);
|
||||
|
||||
decimal rank = score.score.rank / 6;
|
||||
var odd = (rank % 2 != 0);
|
||||
|
||||
_ = embed.AddField(new DiscordEmbedField($"{score.leaderboard.songName.FullSanitize()}{(!string.IsNullOrWhiteSpace(score.leaderboard.songSubName) ? $" {score.leaderboard.songSubName.FullSanitize()}" : "")} - {score.leaderboard.songAuthorName.FullSanitize()} [{score.leaderboard.levelAuthorName.FullSanitize()}]".TruncateWithIndication(256),
|
||||
$":globe_with_meridians: **#{score.score.rank}** | {Formatter.Timestamp(score.score.timeSet, TimestampFormat.RelativeTime)}\n" +
|
||||
$"{(score.leaderboard.ranked ? $"**`{((decimal)((decimal)score.score.modifiedScore / (decimal)score.leaderboard.maxScore) * 100).ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}%`** | **`{(score.score.pp).ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}pp [{(score.score.pp * score.score.weight).ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}pp]`**\n" : "\n")}" +
|
||||
$"`{score.score.modifiedScore.ToString("N0", CultureInfo.CreateSpecificCulture("en-US"))}` | **{(score.score.fullCombo ? "✅ `FC`" : $"{false.ToEmote(ctx.Bot)} `{score.score.missedNotes + score.score.badCuts}`")}**\n" +
|
||||
$"{cmd.GetString(CommandKey.Profile.MapLeaderboard)}: `{ctx.Prefix}scoresaber map-leaderboard {score.leaderboard.difficulty.leaderboardId} {page}{(odd ? " 1" : "")}`"));
|
||||
}
|
||||
|
||||
DiscordMessageBuilder builder = new();
|
||||
|
||||
if (ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId == 0 && AddLinkButton)
|
||||
_ = builder.AddComponents(LinkButton);
|
||||
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(builder.WithEmbed(embed).AddComponents((scoreType == ScoreType.Top ? TopScoreInteractionRow : RecentScoreInteractionRow)));
|
||||
}
|
||||
|
||||
var LoadedGraph = "";
|
||||
|
||||
async Task ShowProfile()
|
||||
{
|
||||
embed = embed.AsInfo(ctx, "Score Saber");
|
||||
|
||||
_ = embed.ClearFields();
|
||||
embed.Title = $"{player.name.FullSanitize()} | `{player.pp.ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}pp`";
|
||||
embed.Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail { Url = player.profilePicture };
|
||||
if (!player.inactive)
|
||||
embed.Description = $":globe_with_meridians: **#{player.rank}** | :flag_{player.country.ToLower()}: **#{player.countryRank}**\n";
|
||||
else
|
||||
embed.Description = $"{cmd.GetString(CommandKey.Profile.InactiveUser, true)}";
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.RankedPlayCount), $"`{player.scoreStats.rankedPlayCount}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.TotalRankedScore), $"`{player.scoreStats.totalRankedScore.ToString("N0", CultureInfo.GetCultureInfo("en-US"))}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.AverageRankedAccuracy), $"`{Math.Round(player.scoreStats.averageRankedAccuracy, 2).ToString().Replace(",", ".")}%`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.TotalPlayCount), $"`{player.scoreStats.totalPlayCount}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.TotalScore), $"`{player.scoreStats.totalScore.ToString("N", CultureInfo.GetCultureInfo("en-US")).Replace(".000", "")}`", true));
|
||||
_ = embed.AddField(new DiscordEmbedField(cmd.GetString(CommandKey.Profile.ReplaysWatched), $"`{player.scoreStats.replaysWatched}`", true));
|
||||
|
||||
DiscordMessageBuilder builder = new();
|
||||
|
||||
if (ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId == 0 && AddLinkButton)
|
||||
_ = builder.AddComponents(LinkButton);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(LoadedGraph))
|
||||
{
|
||||
embed = embed.AsInfo(ctx, "Score Saber");
|
||||
embed.ImageUrl = LoadedGraph;
|
||||
_ = builder.AddComponents(ProfileInteractionRow);
|
||||
}
|
||||
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(builder.WithEmbed(embed));
|
||||
|
||||
var file = $"{Guid.NewGuid()}.png";
|
||||
|
||||
var labels = new List<string>();
|
||||
|
||||
for (var i = 50; i >= 0; i -= 2)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
labels.Add(cmd.GetString(CommandKey.Profile.GraphToday));
|
||||
break;
|
||||
}
|
||||
if (i == 2)
|
||||
{
|
||||
labels.Add(cmd.GetString(CommandKey.Profile.GraphDays, false, new TVar("Count", i)));
|
||||
continue;
|
||||
}
|
||||
|
||||
labels.Add(cmd.GetString(CommandKey.Profile.GraphDays, false, new TVar("Count", i)));
|
||||
labels.Add("");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(LoadedGraph))
|
||||
try
|
||||
{
|
||||
if (player.inactive)
|
||||
throw new Exception("Player is inactive");
|
||||
|
||||
var qc = ctx.Bot.ChartsClient.GetChart(1000, 500, labels, new ChartGeneration.Dataset[]
|
||||
{
|
||||
new(cmd.GetString(CommandKey.Profile.Placement),
|
||||
player.histories.Split(",").Append(player.rank.ToString()),
|
||||
"getGradientFillHelper('vertical', ['#6b76da', '#a336eb', '#FC0000'])", "yaxis2", true),
|
||||
}, -1, -1);
|
||||
|
||||
qc.ToFile(file);
|
||||
|
||||
using var stream = File.Open(file, FileMode.Open);
|
||||
|
||||
var asset = await (await ctx.Client.GetChannelAsync(ctx.Bot.status.SafeReadOnlyConfig.Channels.GraphAssets)).SendMessageAsync(new DiscordMessageBuilder().WithFile(file, stream));
|
||||
|
||||
LoadedGraph = asset.Attachments[0].Url;
|
||||
|
||||
embed = embed.AsInfo(ctx, "Score Saber");
|
||||
embed.ImageUrl = asset.Attachments[0].Url;
|
||||
builder = builder.WithEmbed(embed);
|
||||
_ = builder.AddComponents(ProfileInteractionRow);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(builder);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
embed = embed.AsInfo(ctx, "Score Saber");
|
||||
_ = builder.AddComponents(ProfileInteractionRow);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(builder);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
File.Delete(file);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
_ = ShowProfile().Add(ctx.Bot, ctx);
|
||||
|
||||
ctx.Client.ComponentInteractionCreated += RunInteraction;
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(120000, cancellationTokenSource.Token);
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
ctx.BaseCommand.ModifyToTimedOut(true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
embed.Description = cmd.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
embed.Description = cmd.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
embed.Description = cmd.GetString(CommandKey.Profile.InvalidId, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
catch (UnprocessableEntityException)
|
||||
{
|
||||
embed.Description = cmd.GetString(CommandKey.Profile.InvalidId, true);
|
||||
_ = await ctx.BaseCommand.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
220
Commands/ScoreSaberMapLeaderboardCommand.cs
Normal file
220
Commands/ScoreSaberMapLeaderboardCommand.cs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
// 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
|
||||
|
||||
using System.Globalization;
|
||||
using ProjectMakoto.Entities.ScoreSaber;
|
||||
using ProjectMakoto.Exceptions;
|
||||
using ProjectMakoto.Plugins.ScoreSaber;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ScoreSaberMapLeaderboardCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = ((Plugins.ScoreSaber.Entities.Translations)ScoreSaberPlugin.Plugin!.Translations).Commands.ScoreSaber;
|
||||
|
||||
var boardId = (int)arguments["leaderboardid"];
|
||||
var Page = (uint)arguments["page"];
|
||||
var Internal_Page = (int)arguments["internal_page"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
if (Page <= 0 || !(Internal_Page is 0 or 1))
|
||||
{
|
||||
this.SendSyntaxError();
|
||||
return;
|
||||
}
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.MapLeaderboard.LoadingScoreboard, true)
|
||||
}.AsLoading(ctx, "Score Saber");
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed));
|
||||
|
||||
var NextPageId = Guid.NewGuid().ToString();
|
||||
var PrevPageId = Guid.NewGuid().ToString();
|
||||
|
||||
var InternalPage = Internal_Page;
|
||||
|
||||
var scoreSaberPage = Page;
|
||||
|
||||
Leaderboard leaderboard;
|
||||
|
||||
int TotalPages;
|
||||
|
||||
try
|
||||
{
|
||||
leaderboard = await ScoreSaberPlugin.ScoreSaber!.GetScoreboardById(boardId.ToString());
|
||||
var scores = await ScoreSaberPlugin.ScoreSaber!.GetScoreboardScoresById(boardId.ToString());
|
||||
|
||||
TotalPages = scores.Metadata.TotalPages / scores.Metadata.ItemCount;
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.MapLeaderboard.ScoreboardNotExist, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
throw;
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
CancellationTokenSource cancellationTokenSource = new();
|
||||
Dictionary<uint, LeaderboardScores> cachedPages = new();
|
||||
|
||||
ctx.Client.ComponentInteractionCreated += RunInteraction;
|
||||
|
||||
async Task RunInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (e.Message?.Id == ctx.ResponseMessage.Id && e.User.Id == ctx.User.Id)
|
||||
{
|
||||
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
cancellationTokenSource.Cancel();
|
||||
cancellationTokenSource = new();
|
||||
|
||||
if (e.GetCustomId() == NextPageId)
|
||||
{
|
||||
if (InternalPage == 1)
|
||||
{
|
||||
InternalPage = 0;
|
||||
|
||||
scoreSaberPage++;
|
||||
}
|
||||
else if (InternalPage == 0)
|
||||
{
|
||||
InternalPage = 1;
|
||||
}
|
||||
|
||||
await SendPage(InternalPage, scoreSaberPage);
|
||||
}
|
||||
else if (e.GetCustomId() == PrevPageId)
|
||||
{
|
||||
if (InternalPage == 1)
|
||||
{
|
||||
InternalPage = 0;
|
||||
}
|
||||
else if (InternalPage == 0)
|
||||
{
|
||||
InternalPage = 1;
|
||||
|
||||
scoreSaberPage--;
|
||||
}
|
||||
|
||||
await SendPage(InternalPage, scoreSaberPage);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(60000, cancellationTokenSource.Token);
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
this.ModifyToTimedOut();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
|
||||
async Task SendPage(int internalPage, uint scoreSaberPage)
|
||||
{
|
||||
if (scoreSaberPage > TotalPages)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.MapLeaderboard.PageNotExist, true, new TVar("Page", scoreSaberPage));
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
|
||||
LeaderboardScores scores;
|
||||
try
|
||||
{
|
||||
if (!cachedPages.ContainsKey(scoreSaberPage))
|
||||
cachedPages.Add(scoreSaberPage, await ScoreSaberPlugin.ScoreSaber!.GetScoreboardScoresById(boardId.ToString(), scoreSaberPage));
|
||||
|
||||
scores = cachedPages[scoreSaberPage];
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.MapLeaderboard.ScoreboardNotExist, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
throw;
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
embed = embed.AsInfo(ctx, "Score Saber");
|
||||
embed.Title = $"{leaderboard.leaderboardInfo.songName.FullSanitize()}{(!string.IsNullOrWhiteSpace(leaderboard.leaderboardInfo.songSubName) ? $" {leaderboard.leaderboardInfo.songSubName.FullSanitize()}" : "")} - {leaderboard.leaderboardInfo.songAuthorName.FullSanitize()} [{leaderboard.leaderboardInfo.levelAuthorName.FullSanitize()}]".TruncateWithIndication(256);
|
||||
embed.Description = "";
|
||||
embed.Author.IconUrl = ctx.Guild.IconUrl;
|
||||
embed.Thumbnail = new DiscordEmbedBuilder.EmbedThumbnail { Url = leaderboard.leaderboardInfo.coverImage };
|
||||
embed.Footer = ctx.GenerateUsedByFooter($"{this.GetString(this.t.Common.Page)} {scoreSaberPage}/{TotalPages}");
|
||||
_ = embed.ClearFields();
|
||||
foreach (var score in scores.Scores.ToList().Skip(internalPage * 6).Take(6))
|
||||
{
|
||||
_ = embed.AddField(new DiscordEmbedField($"**#{score.Rank}** {score.Player.Country.IsoCountryCodeToFlagEmoji()} `{score.Player.Name.SanitizeForCode()}` | {Formatter.Timestamp(score.Timestamp, TimestampFormat.RelativeTime)}",
|
||||
$"{(leaderboard.leaderboardInfo.ranked ? $"**`{((decimal)((decimal)score.ModifiedScore / (decimal)leaderboard.leaderboardInfo.maxScore) * 100).ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}%`** | **`{(score.PP).ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}pp`** | " : " | ")}" +
|
||||
$"`{score.ModifiedScore.ToString("N0", CultureInfo.CreateSpecificCulture("en-US"))}` | **{(score.FullCombo ? "✅ `FC`" : $"{false.ToEmote(ctx.Bot)} `{score.MissedNotes + score.BadCuts}`")}**\n" +
|
||||
$"{this.GetString(CommandKey.MapLeaderboard.Profile)}: `{ctx.Prefix}scoresaber profile {score.Player.Id}`"));
|
||||
}
|
||||
|
||||
var previousPageButton = new DiscordButtonComponent(ButtonStyle.Primary, PrevPageId, this.GetString(this.t.Common.PreviousPage), (scoreSaberPage + InternalPage - 1 <= 0), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("◀")));
|
||||
var nextPageButton = new DiscordButtonComponent(ButtonStyle.Primary, NextPageId, this.GetString(this.t.Common.NextPage), (scoreSaberPage + 1 > scores.Metadata.TotalPages / scores.Metadata.ItemCount), new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶")));
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(new List<DiscordComponent> { previousPageButton, nextPageButton }));
|
||||
};
|
||||
|
||||
await SendPage(InternalPage, scoreSaberPage);
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(60000, cancellationTokenSource.Token);
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunInteraction;
|
||||
|
||||
this.ModifyToTimedOut();
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
}
|
||||
79
Commands/ScoreSaberProfileCommand.cs
Normal file
79
Commands/ScoreSaberProfileCommand.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// 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
|
||||
|
||||
using System.Text.RegularExpressions;
|
||||
using ProjectMakoto.Plugins.ScoreSaber;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ScoreSaberProfileCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = ((Plugins.ScoreSaber.Entities.Translations)ScoreSaberPlugin.Plugin!.Translations).Commands.ScoreSaber;
|
||||
|
||||
var id = (string)arguments["profile"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
var AddLinkButton = true;
|
||||
|
||||
if ((string.IsNullOrWhiteSpace(id) || id.Contains('@')))
|
||||
{
|
||||
DiscordUser user;
|
||||
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
if (Regex.IsMatch(id, @"<@((!?)(\d*))>", RegexOptions.ExplicitCapture))
|
||||
user = await ctx.Client.GetUserAsync(Convert.ToUInt64(Regex.Match(id, @"<@((!?)(\d*))>").Groups[3].Value));
|
||||
else
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Profile.InvalidInput, true)
|
||||
}.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
user = ctx.User;
|
||||
}
|
||||
catch (DisCatSharp.Exceptions.NotFoundException)
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Profile.NoUser, true)
|
||||
}.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId != 0)
|
||||
{
|
||||
id = ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId.ToString();
|
||||
AddLinkButton = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Profile.NoProfile, true)
|
||||
}.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await ScoreSaberCommandAbstractions.SendScoreSaberProfile(ctx, this, id, AddLinkButton);
|
||||
});
|
||||
}
|
||||
}
|
||||
313
Commands/ScoreSaberSearchCommand.cs
Normal file
313
Commands/ScoreSaberSearchCommand.cs
Normal file
|
|
@ -0,0 +1,313 @@
|
|||
// 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
|
||||
|
||||
using System.Globalization;
|
||||
using ProjectMakoto.Entities.ScoreSaber;
|
||||
using ProjectMakoto.Exceptions;
|
||||
using ProjectMakoto.Plugins.ScoreSaber;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ScoreSaberSearchCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = ((Plugins.ScoreSaber.Entities.Translations)ScoreSaberPlugin.Plugin!.Translations).Commands.ScoreSaber;
|
||||
|
||||
var name = (string)arguments["name"];
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
DiscordStringSelectComponent GetContinents(string default_code)
|
||||
{
|
||||
List<DiscordStringSelectComponentOption> continents = new() { new DiscordStringSelectComponentOption(this.GetString(CommandKey.Search.NoCountryFilter), "no_country", "", (default_code == "no_country")) };
|
||||
foreach (var b in ctx.Bot.CountryCodes.List.GroupBy(x => x.Value.ContinentCode).Select(x => x.First()).Take(24))
|
||||
{
|
||||
continents.Add(new DiscordStringSelectComponentOption($"{b.Value.ContinentName}", b.Value.ContinentCode, "", (default_code == b.Value.ContinentCode)));
|
||||
}
|
||||
return new DiscordStringSelectComponent(this.GetString(CommandKey.Search.SelectContinentDropdown), continents as IEnumerable<DiscordStringSelectComponentOption>, "continent_selection");
|
||||
}
|
||||
|
||||
DiscordStringSelectComponent GetCountries(string continent_code, string default_country, int page)
|
||||
{
|
||||
List<DiscordStringSelectComponentOption> countries = new();
|
||||
var currentCountryList = ctx.Bot.CountryCodes.List.Where(x => x.Value.ContinentCode.ToLower() == continent_code.ToLower()).Skip((page - 1) * 25).Take(25).ToList();
|
||||
|
||||
foreach (var b in currentCountryList)
|
||||
{
|
||||
DiscordEmoji flag_emote = null;
|
||||
try
|
||||
{ flag_emote = DiscordEmoji.FromName(ctx.Client, $":flag_{b.Key.ToLower()}:"); }
|
||||
catch (Exception) { flag_emote = DiscordEmoji.FromUnicode("⬜"); }
|
||||
countries.Add(new DiscordStringSelectComponentOption($"{b.Value.Name}", b.Key, "", (b.Key == default_country), new DiscordComponentEmoji(flag_emote)));
|
||||
}
|
||||
return new DiscordStringSelectComponent(this.GetString(CommandKey.Search.SelectCountryDropdown), countries as IEnumerable<DiscordStringSelectComponentOption>, "country_selection");
|
||||
}
|
||||
|
||||
var start_search_button = new DiscordButtonComponent(ButtonStyle.Success, "start_search", this.GetString(CommandKey.Search.StartSearch), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("🔎")));
|
||||
var next_step_button = new DiscordButtonComponent(ButtonStyle.Primary, "next_step", this.GetString(CommandKey.Search.NextStep), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶")));
|
||||
|
||||
var previous_page_button = new DiscordButtonComponent(ButtonStyle.Primary, "prev_page", this.GetString(this.t.Common.PreviousPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("◀")));
|
||||
var next_page_button = new DiscordButtonComponent(ButtonStyle.Primary, "next_page", this.GetString(this.t.Common.NextPage), false, new DiscordComponentEmoji(DiscordEmoji.FromUnicode("▶")));
|
||||
|
||||
var embed = new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Search.SelectContinent, true)
|
||||
}.AsAwaitingInput(ctx, "Score Saber");
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(GetContinents("no_country")).AddComponents(start_search_button));
|
||||
CancellationTokenSource tokenSource = new();
|
||||
|
||||
var selectedContinent = "no_country";
|
||||
var selectedCountry = "no_country";
|
||||
var lastFetchedPage = -1;
|
||||
var currentPage = 1;
|
||||
var currentFetchedPage = 1;
|
||||
var playerSelection = false;
|
||||
PlayerSearch lastSearch = null;
|
||||
|
||||
async Task RunDropdownInteraction(DiscordClient s, ComponentInteractionCreateEventArgs e)
|
||||
{
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.Message?.Id == ctx.ResponseMessage.Id && e.User.Id == ctx.User.Id)
|
||||
{
|
||||
_ = e.Interaction.CreateResponseAsync(InteractionResponseType.DeferredMessageUpdate);
|
||||
|
||||
async Task RefreshCountryList()
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.Search.SelectCountry, true);
|
||||
|
||||
if (selectedCountry != "no_country")
|
||||
{
|
||||
embed.Description += $"\n`{this.GetString(CommandKey.Search.SelectedCountry)}: '{ctx.Bot.CountryCodes.List[selectedCountry].Name}'`";
|
||||
}
|
||||
|
||||
var page = GetCountries(selectedContinent, selectedCountry, currentPage);
|
||||
var builder = new DiscordMessageBuilder().WithEmbed(embed).AddComponents(page);
|
||||
|
||||
if (currentPage == 1 && ctx.Bot.CountryCodes.List.Where(x => x.Value.ContinentCode.ToLower() == selectedContinent.ToLower()).Count() > 25)
|
||||
{
|
||||
_ = builder.AddComponents(next_page_button);
|
||||
}
|
||||
|
||||
if (currentPage != 1)
|
||||
{
|
||||
if (ctx.Bot.CountryCodes.List.Where(x => x.Value.ContinentCode.ToLower() == selectedContinent.ToLower()).Skip((currentPage - 1) * 25).Count() > 25)
|
||||
_ = builder.AddComponents(next_page_button);
|
||||
|
||||
_ = builder.AddComponents(previous_page_button);
|
||||
}
|
||||
|
||||
if (selectedCountry != "no_country")
|
||||
_ = builder.AddComponents(start_search_button);
|
||||
|
||||
_ = await this.RespondOrEdit(builder);
|
||||
}
|
||||
|
||||
async Task RefreshPlayerList()
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
embed.Description = this.GetString(CommandKey.Search.Searching, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsLoading(ctx, "Score Saber")));
|
||||
|
||||
if (currentFetchedPage != lastFetchedPage)
|
||||
{
|
||||
try
|
||||
{
|
||||
lastSearch = await ScoreSaberPlugin.ScoreSaber!.SearchPlayer(name, currentFetchedPage, (selectedCountry != "no_country" ? selectedCountry : ""));
|
||||
}
|
||||
catch (InternalServerErrorException)
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
|
||||
embed.Description = this.GetString(CommandKey.InternalServerError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (ForbiddenException)
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
|
||||
embed.Description = this.GetString(CommandKey.ForbiddenError, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
lastFetchedPage = currentFetchedPage;
|
||||
}
|
||||
|
||||
List<DiscordStringSelectComponentOption> playerDropDownOptions = new();
|
||||
var playerList = lastSearch.players.Skip((currentPage - 1) * 25).Take(25).ToList();
|
||||
foreach (var b in playerList)
|
||||
{
|
||||
playerDropDownOptions.Add(new DiscordStringSelectComponentOption($"{b.name.FullSanitize()} | {b.pp.ToString("N2", CultureInfo.CreateSpecificCulture("en-US"))}pp", b.id, $"🌐 #{b.rank} | {b.country.IsoCountryCodeToFlagEmoji()} #{b.countryRank}"));
|
||||
}
|
||||
var player_dropdown = new DiscordStringSelectComponent(this.GetString(CommandKey.Search.SelectPlayer), playerDropDownOptions as IEnumerable<DiscordStringSelectComponentOption>, "player_selection");
|
||||
|
||||
var builder = new DiscordMessageBuilder().AddComponents(player_dropdown);
|
||||
|
||||
var added_next = false;
|
||||
|
||||
if (currentPage == 1 && lastSearch.players.Length > 25)
|
||||
{
|
||||
_ = builder.AddComponents(next_page_button);
|
||||
added_next = true;
|
||||
}
|
||||
|
||||
if (currentPage != 1 || lastFetchedPage != 1)
|
||||
{
|
||||
if ((lastSearch.players.Skip((currentPage - 1) * 25).Take(25).Count() > 25 || ((((lastSearch.metadata.total - (currentFetchedPage - 1)) * 50) > 0) && player_dropdown.Options.Count == 25)) && !added_next)
|
||||
_ = builder.AddComponents(next_page_button);
|
||||
|
||||
_ = builder.AddComponents(previous_page_button);
|
||||
}
|
||||
|
||||
ctx.Client.ComponentInteractionCreated += RunDropdownInteraction;
|
||||
|
||||
embed.Description = this.GetString(CommandKey.Search.FoundCount, true, new TVar("TotalCount", lastSearch.metadata.total));
|
||||
_ = await this.RespondOrEdit(builder.WithEmbed(embed.AsSuccess(ctx, "Score Saber")));
|
||||
}
|
||||
|
||||
if (e.GetCustomId() == "start_search")
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
|
||||
playerSelection = true;
|
||||
currentPage = 1;
|
||||
await RefreshPlayerList();
|
||||
|
||||
tokenSource = new();
|
||||
}
|
||||
else if (e.GetCustomId() == "player_selection")
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
|
||||
await ScoreSaberCommandAbstractions.SendScoreSaberProfile(ctx, this, e.Values.First());
|
||||
return;
|
||||
}
|
||||
else if (e.GetCustomId() == "next_step")
|
||||
{
|
||||
_ = RefreshCountryList();
|
||||
}
|
||||
else if (e.GetCustomId() == "country_selection")
|
||||
{
|
||||
selectedCountry = e.Values.First();
|
||||
|
||||
_ = RefreshCountryList();
|
||||
}
|
||||
else if (e.GetCustomId() == "prev_page")
|
||||
{
|
||||
if (playerSelection)
|
||||
{
|
||||
if (currentPage == 1)
|
||||
{
|
||||
currentPage = 2;
|
||||
currentFetchedPage -= 1;
|
||||
}
|
||||
else
|
||||
currentPage -= 1;
|
||||
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
|
||||
await RefreshPlayerList();
|
||||
|
||||
tokenSource = new();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPage -= 1;
|
||||
_ = RefreshCountryList();
|
||||
}
|
||||
}
|
||||
else if (e.GetCustomId() == "next_page")
|
||||
{
|
||||
if (playerSelection)
|
||||
{
|
||||
if (currentPage == 2)
|
||||
{
|
||||
currentPage = 1;
|
||||
currentFetchedPage += 1;
|
||||
}
|
||||
else
|
||||
currentPage += 1;
|
||||
|
||||
tokenSource.Cancel();
|
||||
tokenSource = null;
|
||||
|
||||
await RefreshPlayerList();
|
||||
|
||||
tokenSource = new();
|
||||
}
|
||||
else
|
||||
{
|
||||
currentPage += 1;
|
||||
_ = RefreshCountryList();
|
||||
}
|
||||
}
|
||||
else if (e.GetCustomId() == "continent_selection")
|
||||
{
|
||||
selectedContinent = e.Values.First();
|
||||
|
||||
_ = selectedContinent != "no_country"
|
||||
? await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(GetContinents(selectedContinent)).AddComponents(next_step_button))
|
||||
: await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed).AddComponents(GetContinents(selectedContinent)).AddComponents(start_search_button));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
tokenSource.Cancel();
|
||||
tokenSource = new();
|
||||
await Task.Delay(120000, tokenSource.Token);
|
||||
this.ModifyToTimedOut();
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch (NotFoundException)
|
||||
{
|
||||
embed.Description = this.GetString(CommandKey.Search.NoSearchResult, true);
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(embed.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
throw;
|
||||
}
|
||||
}).Add(ctx.Bot, ctx);
|
||||
}
|
||||
ctx.Client.ComponentInteractionCreated += RunDropdownInteraction;
|
||||
|
||||
try
|
||||
{
|
||||
await Task.Delay(120000, tokenSource.Token);
|
||||
this.ModifyToTimedOut();
|
||||
|
||||
ctx.Client.ComponentInteractionCreated -= RunDropdownInteraction;
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
}
|
||||
43
Commands/ScoreSaberUnlinkCommand.cs
Normal file
43
Commands/ScoreSaberUnlinkCommand.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// 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
|
||||
|
||||
using ProjectMakoto.Plugins.ScoreSaber;
|
||||
|
||||
namespace ProjectMakoto.Commands;
|
||||
|
||||
internal sealed class ScoreSaberUnlinkCommand : BaseCommand
|
||||
{
|
||||
public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary<string, object> arguments)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
var CommandKey = ((Plugins.ScoreSaber.Entities.Translations)ScoreSaberPlugin.Plugin!.Translations).Commands.ScoreSaber;
|
||||
|
||||
if (await ctx.DbUser.Cooldown.WaitForHeavy(ctx))
|
||||
return;
|
||||
|
||||
if (ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId != 0)
|
||||
{
|
||||
ScoreSaberPlugin.Plugin!.Users![ctx.User.Id].ScoreSaberId = 0;
|
||||
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Unlink.Unlinked, true)
|
||||
}.AsSuccess(ctx, "Score Saber")));
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = await this.RespondOrEdit(new DiscordMessageBuilder().WithEmbed(new DiscordEmbedBuilder
|
||||
{
|
||||
Description = this.GetString(CommandKey.Unlink.NoLink, true)
|
||||
}.AsError(ctx, "Score Saber")));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue