More common refactorings like renaming variables, removing empty statements and unused variables, etc

This commit is contained in:
Kwoth
2022-01-09 16:46:08 +01:00
parent 2ce3262d59
commit f07a855912
75 changed files with 447 additions and 465 deletions

View File

@@ -62,7 +62,10 @@ namespace NadekoBot.Tests
collection.Clear(); collection.Clear();
Assert.IsTrue(collection.Count == 0, "Collection has not been cleared."); Assert.IsTrue(collection.Count == 0, "Collection has not been cleared.");
Assert.Throws<ArgumentOutOfRangeException>(() => collection.Contains(collection[0]), "Collection has not been cleared."); Assert.Throws<ArgumentOutOfRangeException>(() =>
{
_ = collection[0];
}, "Collection has not been cleared.");
} }
[Test] [Test]

View File

@@ -10,7 +10,7 @@ public class CommentGatheringTypeInspector : TypeInspectorSkeleton
private readonly ITypeInspector _innerTypeDescriptor; private readonly ITypeInspector _innerTypeDescriptor;
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
=> this._innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor"); => _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor");
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container) public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
=> _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); => _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
@@ -43,7 +43,7 @@ public class CommentGatheringTypeInspector : TypeInspectorSkeleton
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
{ {
this._baseDescriptor = baseDescriptor; _baseDescriptor = baseDescriptor;
Name = baseDescriptor.Name; Name = baseDescriptor.Name;
} }

View File

@@ -24,7 +24,7 @@ public sealed class CommentsObjectDescriptor : IObjectDescriptor
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
{ {
this._innerDescriptor = innerDescriptor; _innerDescriptor = innerDescriptor;
Comment = comment; Comment = comment;
} }
} }

View File

@@ -9,7 +9,7 @@ public static class QuoteExtensions
public static IEnumerable<Quote> GetForGuild(this DbSet<Quote> quotes, ulong guildId) public static IEnumerable<Quote> GetForGuild(this DbSet<Quote> quotes, ulong guildId)
=> quotes.AsQueryable().Where(x => x.GuildId == guildId); => quotes.AsQueryable().Where(x => x.GuildId == guildId);
public static IEnumerable<Quote> GetGroup( public static IReadOnlyCollection<Quote> GetGroup(
this DbSet<Quote> quotes, this DbSet<Quote> quotes,
ulong guildId, ulong guildId,
int page, int page,

View File

@@ -361,7 +361,7 @@ WHERE GuildId={guildId}
.ToArray(); .ToArray();
} }
public (IEnumerable<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill( public (IReadOnlyCollection<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill(
SocketGuild guild, SocketGuild guild,
string people) string people)
{ {

View File

@@ -36,7 +36,7 @@ public partial class Gambling
[NadekoOptionsAttribute(typeof(RaceOptions))] [NadekoOptionsAttribute(typeof(RaceOptions))]
public partial Task Race(params string[] args) public partial Task Race(params string[] args)
{ {
var (options, success) = OptionsParser.ParseFrom(new RaceOptions(), args); var (options, _) = OptionsParser.ParseFrom(new RaceOptions(), args);
var ar = new AnimalRace(options, _cs, _gamesConf.Data.RaceAnimals.Shuffle()); var ar = new AnimalRace(options, _cs, _gamesConf.Data.RaceAnimals.Shuffle());
if (!_service.AnimalRaces.TryAdd(ctx.Guild.Id, ar)) if (!_service.AnimalRaces.TryAdd(ctx.Guild.Id, ar))
@@ -46,7 +46,7 @@ public partial class Gambling
var count = 0; var count = 0;
Task _client_MessageReceived(SocketMessage arg) Task ClientMessageReceived(SocketMessage arg)
{ {
_= Task.Run(() => _= Task.Run(() =>
{ {
@@ -61,9 +61,9 @@ public partial class Gambling
return Task.CompletedTask; return Task.CompletedTask;
} }
Task Ar_OnEnded(AnimalRace race) Task ArOnEnded(AnimalRace race)
{ {
_client.MessageReceived -= _client_MessageReceived; _client.MessageReceived -= ClientMessageReceived;
_service.AnimalRaces.TryRemove(ctx.Guild.Id, out _); _service.AnimalRaces.TryRemove(ctx.Guild.Id, out _);
var winner = race.FinishedUsers[0]; var winner = race.FinishedUsers[0];
if (race.FinishedUsers[0].Bet > 0) if (race.FinishedUsers[0].Bet > 0)
@@ -77,9 +77,9 @@ public partial class Gambling
ar.OnStartingFailed += Ar_OnStartingFailed; ar.OnStartingFailed += Ar_OnStartingFailed;
ar.OnStateUpdate += Ar_OnStateUpdate; ar.OnStateUpdate += Ar_OnStateUpdate;
ar.OnEnded += Ar_OnEnded; ar.OnEnded += ArOnEnded;
ar.OnStarted += Ar_OnStarted; ar.OnStarted += Ar_OnStarted;
_client.MessageReceived += _client_MessageReceived; _client.MessageReceived += ClientMessageReceived;
return SendConfirmAsync(GetText(strs.animal_race), return SendConfirmAsync(GetText(strs.animal_race),
GetText(strs.animal_race_starting(options.StartTime)), GetText(strs.animal_race_starting(options.StartTime)),

View File

@@ -34,7 +34,7 @@ public partial class Gambling
if (!await CheckBetMandatory(amount)) if (!await CheckBetMandatory(amount))
return; return;
var newBj = new Blackjack(_cs, _db); var newBj = new Blackjack(_cs);
Blackjack bj; Blackjack bj;
if (newBj == (bj = _service.Games.GetOrAdd(ctx.Channel.Id, newBj))) if (newBj == (bj = _service.Games.GetOrAdd(ctx.Channel.Id, newBj)))
{ {

View File

@@ -21,16 +21,14 @@ public class Blackjack
public GameState State { get; set; } = GameState.Starting; public GameState State { get; set; } = GameState.Starting;
public User CurrentUser { get; private set; } public User CurrentUser { get; private set; }
private TaskCompletionSource<bool> _currentUserMove; private TaskCompletionSource<bool> currentUserMove;
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly DbService _db;
private readonly SemaphoreSlim _locker = new(1, 1); private readonly SemaphoreSlim _locker = new(1, 1);
public Blackjack(ICurrencyService cs, DbService db) public Blackjack(ICurrencyService cs)
{ {
_cs = cs; _cs = cs;
_db = db;
Dealer = new(); Dealer = new();
} }
@@ -58,7 +56,7 @@ public class Blackjack
if (!Players.Any()) if (!Players.Any())
{ {
State = GameState.Ended; State = GameState.Ended;
var end = GameEnded?.Invoke(this); _ = GameEnded?.Invoke(this);
return; return;
} }
@@ -101,14 +99,14 @@ public class Blackjack
{ {
var pause = Task.Delay(20000); //10 seconds to decide var pause = Task.Delay(20000); //10 seconds to decide
CurrentUser = usr; CurrentUser = usr;
_currentUserMove = new(); currentUserMove = new();
await PrintState(); await PrintState();
// either wait for the user to make an action and // either wait for the user to make an action and
// if he doesn't - stand // if he doesn't - stand
var finished = await Task.WhenAny(pause, _currentUserMove.Task); var finished = await Task.WhenAny(pause, currentUserMove.Task);
if (finished == pause) await Stand(usr); if (finished == pause) await Stand(usr);
CurrentUser = null; CurrentUser = null;
_currentUserMove = null; currentUserMove = null;
} }
public async Task<bool> Join(IUser user, long bet) public async Task<bool> Join(IUser user, long bet)
@@ -156,7 +154,7 @@ public class Blackjack
return false; return false;
u.State = User.UserState.Stand; u.State = User.UserState.Stand;
_currentUserMove.TrySetResult(true); currentUserMove.TrySetResult(true);
return true; return true;
} }
finally finally
@@ -252,7 +250,7 @@ public class Blackjack
else else
//with double you just get one card, and then you're done //with double you just get one card, and then you're done
u.State = User.UserState.Stand; u.State = User.UserState.Stand;
_currentUserMove.TrySetResult(true); currentUserMove.TrySetResult(true);
return true; return true;
} }
@@ -292,7 +290,7 @@ public class Blackjack
// user busted // user busted
u.State = User.UserState.Bust; u.State = User.UserState.Bust;
_currentUserMove.TrySetResult(true); currentUserMove.TrySetResult(true);
return true; return true;
} }

View File

@@ -59,7 +59,7 @@ public sealed class Connect4Game : IDisposable
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
private readonly NadekoRandom _rng; private readonly NadekoRandom _rng;
private Timer _playerTimeoutTimer; private Timer playerTimeoutTimer;
/* [ ][ ][ ][ ][ ][ ] /* [ ][ ][ ][ ][ ][ ]
* [ ][ ][ ][ ][ ][ ] * [ ][ ][ ][ ][ ][ ]
@@ -133,7 +133,7 @@ public sealed class Connect4Game : IDisposable
} }
CurrentPhase = Phase.P1Move; //start the game CurrentPhase = Phase.P1Move; //start the game
_playerTimeoutTimer = new(async _ => playerTimeoutTimer = new(async _ =>
{ {
await _locker.WaitAsync(); await _locker.WaitAsync();
try try
@@ -330,7 +330,7 @@ public sealed class Connect4Game : IDisposable
} }
private void ResetTimer() private void ResetTimer()
=> _playerTimeoutTimer.Change(TimeSpan.FromSeconds(_options.TurnTimer), => playerTimeoutTimer.Change(TimeSpan.FromSeconds(_options.TurnTimer),
TimeSpan.FromSeconds(_options.TurnTimer)); TimeSpan.FromSeconds(_options.TurnTimer));
private void EndGame(Result result, ulong? winId) private void EndGame(Result result, ulong? winId)
@@ -369,7 +369,7 @@ public sealed class Connect4Game : IDisposable
OnGameFailedToStart = null; OnGameFailedToStart = null;
OnGameStateUpdated = null; OnGameStateUpdated = null;
OnGameEnded = null; OnGameEnded = null;
_playerTimeoutTimer?.Change(Timeout.Infinite, Timeout.Infinite); playerTimeoutTimer?.Change(Timeout.Infinite, Timeout.Infinite);
} }

View File

@@ -11,19 +11,19 @@ public partial class Gambling
[Group] [Group]
public partial class Connect4Commands : GamblingSubmodule<GamblingService> public partial class Connect4Commands : GamblingSubmodule<GamblingService>
{ {
private static readonly string[] numbers = private static readonly string[] _numbers =
{ {
":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:" ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:"
}; };
private int RepostCounter private int RepostCounter
{ {
get => _repostCounter; get => repostCounter;
set set
{ {
if (value is < 0 or > 7) if (value is < 0 or > 7)
_repostCounter = 0; repostCounter = 0;
else _repostCounter = value; else repostCounter = value;
} }
} }
@@ -32,7 +32,7 @@ public partial class Gambling
private IUserMessage msg; private IUserMessage msg;
private int _repostCounter; private int repostCounter;
public Connect4Commands(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService gamb) public Connect4Commands(DiscordSocketClient client, ICurrencyService cs, GamblingConfigService gamb)
: base(gamb) : base(gamb)
@@ -59,7 +59,7 @@ public partial class Gambling
newGame.Dispose(); newGame.Dispose();
//means game already exists, try to join //means game already exists, try to join
var joined = await game.Join(ctx.User.Id, ctx.User.ToString(), options.Bet); await game.Join(ctx.User.Id, ctx.User.ToString(), options.Bet);
return; return;
} }
@@ -73,9 +73,9 @@ public partial class Gambling
} }
game.OnGameStateUpdated += Game_OnGameStateUpdated; game.OnGameStateUpdated += Game_OnGameStateUpdated;
game.OnGameFailedToStart += Game_OnGameFailedToStart; game.OnGameFailedToStart += GameOnGameFailedToStart;
game.OnGameEnded += Game_OnGameEnded; game.OnGameEnded += GameOnGameEnded;
_client.MessageReceived += _client_MessageReceived; _client.MessageReceived += ClientMessageReceived;
game.Initialize(); game.Initialize();
if (options.Bet == 0) if (options.Bet == 0)
@@ -83,7 +83,7 @@ public partial class Gambling
else else
await ReplyErrorLocalizedAsync(strs.connect4_created_bet(options.Bet + CurrencySign)); await ReplyErrorLocalizedAsync(strs.connect4_created_bet(options.Bet + CurrencySign));
Task _client_MessageReceived(SocketMessage arg) Task ClientMessageReceived(SocketMessage arg)
{ {
if (ctx.Channel.Id != arg.Channel.Id) if (ctx.Channel.Id != arg.Channel.Id)
return Task.CompletedTask; return Task.CompletedTask;
@@ -110,22 +110,22 @@ public partial class Gambling
return Task.CompletedTask; return Task.CompletedTask;
} }
Task Game_OnGameFailedToStart(Connect4Game arg) Task GameOnGameFailedToStart(Connect4Game arg)
{ {
if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose)) if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose))
{ {
_client.MessageReceived -= _client_MessageReceived; _client.MessageReceived -= ClientMessageReceived;
toDispose.Dispose(); toDispose.Dispose();
} }
return ErrorLocalizedAsync(strs.connect4_failed_to_start); return ErrorLocalizedAsync(strs.connect4_failed_to_start);
} }
Task Game_OnGameEnded(Connect4Game arg, Connect4Game.Result result) Task GameOnGameEnded(Connect4Game arg, Connect4Game.Result result)
{ {
if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose)) if (_service.Connect4Games.TryRemove(ctx.Channel.Id, out var toDispose))
{ {
_client.MessageReceived -= _client_MessageReceived; _client.MessageReceived -= ClientMessageReceived;
toDispose.Dispose(); toDispose.Dispose();
} }
@@ -185,7 +185,7 @@ public partial class Gambling
sb.AppendLine(); sb.AppendLine();
} }
for (var i = 0; i < Connect4Game.NUMBER_OF_COLUMNS; i++) sb.Append(numbers[i]); for (var i = 0; i < Connect4Game.NUMBER_OF_COLUMNS; i++) sb.Append(_numbers[i]);
return sb.ToString(); return sb.ToString();
} }
} }

View File

@@ -11,10 +11,10 @@ public partial class Gambling
[Group] [Group]
public partial class DiceRollCommands : NadekoSubmodule public partial class DiceRollCommands : NadekoSubmodule
{ {
private static readonly Regex dndRegex = new(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", private static readonly Regex _dndRegex = new(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$",
RegexOptions.Compiled); RegexOptions.Compiled);
private static readonly Regex fudgeRegex = new(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled); private static readonly Regex _fudgeRegex = new(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
private static readonly char[] _fateRolls = { '-', ' ', '+' }; private static readonly char[] _fateRolls = { '-', ' ', '+' };
private readonly IImageCache _images; private readonly IImageCache _images;
@@ -115,7 +115,7 @@ public partial class Gambling
private async Task InternallDndRoll(string arg, bool ordered) private async Task InternallDndRoll(string arg, bool ordered)
{ {
Match match; Match match;
if ((match = fudgeRegex.Match(arg)).Length != 0 if ((match = _fudgeRegex.Match(arg)).Length != 0
&& int.TryParse(match.Groups["n1"].ToString(), out var n1) && int.TryParse(match.Groups["n1"].ToString(), out var n1)
&& n1 is > 0 and < 500) && n1 is > 0 and < 500)
{ {
@@ -134,7 +134,7 @@ public partial class Gambling
await ctx.Channel.EmbedAsync(embed); await ctx.Channel.EmbedAsync(embed);
} }
else if ((match = dndRegex.Match(arg)).Length != 0) else if ((match = _dndRegex.Match(arg)).Length != 0)
{ {
var rng = new NadekoRandom(); var rng = new NadekoRandom();
if (int.TryParse(match.Groups["n1"].ToString(), out n1) if (int.TryParse(match.Groups["n1"].ToString(), out n1)

View File

@@ -117,7 +117,7 @@ public class GameStatusEvent : ICurrencyEvent
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable) private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
{ {
if (message.Id == this.msg.Id) await StopEvent(); if (message.Id == msg.Id) await StopEvent();
} }
public async Task StopEvent() public async Task StopEvent()

View File

@@ -99,11 +99,11 @@ public class ReactionEvent : ICurrencyEvent
public async Task StartEvent() public async Task StartEvent()
{ {
if (Emote.TryParse(_config.Currency.Sign, out var parsedEmote)) if (Emote.TryParse(_config.Currency.Sign, out var parsedEmote))
this.emote = parsedEmote; emote = parsedEmote;
else else
this.emote = new Emoji(_config.Currency.Sign); emote = new Emoji(_config.Currency.Sign);
msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize)); msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize));
await msg.AddReactionAsync(this.emote); await msg.AddReactionAsync(emote);
_client.MessageDeleted += OnMessageDeleted; _client.MessageDeleted += OnMessageDeleted;
_client.ReactionAdded += HandleReaction; _client.ReactionAdded += HandleReaction;
_t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2)); _t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
@@ -114,7 +114,7 @@ public class ReactionEvent : ICurrencyEvent
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable) private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
{ {
if (message.Id == this.msg.Id) await StopEvent(); if (message.Id == msg.Id) await StopEvent();
} }
public async Task StopEvent() public async Task StopEvent()
@@ -151,7 +151,7 @@ public class ReactionEvent : ICurrencyEvent
if ((r.User.IsSpecified if ((r.User.IsSpecified
? r.User.Value ? r.User.Value
: null) is not IGuildUser gu // no unknown users, as they could be bots, or alts : null) is not IGuildUser gu // no unknown users, as they could be bots, or alts
|| message.Id != this.msg.Id // same message || message.Id != msg.Id // same message
|| gu.IsBot // no bots || gu.IsBot // no bots
|| (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5 // no recently created accounts || (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5 // no recently created accounts
|| (_noRecentlyJoinedServer || (_noRecentlyJoinedServer

View File

@@ -22,7 +22,7 @@ public partial class Gambling
Tails = 2 Tails = 2
} }
private static readonly NadekoRandom rng = new(); private static readonly NadekoRandom _rng = new();
private readonly IImageCache _images; private readonly IImageCache _images;
private readonly ICurrencyService _cs; private readonly ICurrencyService _cs;
@@ -47,9 +47,9 @@ public partial class Gambling
var imgs = new Image<Rgba32>[count]; var imgs = new Image<Rgba32>[count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var headsArr = _images.Heads[rng.Next(0, _images.Heads.Count)]; var headsArr = _images.Heads[_rng.Next(0, _images.Heads.Count)];
var tailsArr = _images.Tails[rng.Next(0, _images.Tails.Count)]; var tailsArr = _images.Tails[_rng.Next(0, _images.Tails.Count)];
if (rng.Next(0, 10) < 5) if (_rng.Next(0, 10) < 5)
{ {
imgs[i] = Image.Load(headsArr); imgs[i] = Image.Load(headsArr);
headCount++; headCount++;
@@ -90,21 +90,21 @@ public partial class Gambling
BetFlipGuess result; BetFlipGuess result;
Uri imageToSend; Uri imageToSend;
var coins = _images.ImageUrls.Coins; var coins = _images.ImageUrls.Coins;
if (rng.Next(0, 1000) <= 499) if (_rng.Next(0, 1000) <= 499)
{ {
imageToSend = coins.Heads[rng.Next(0, coins.Heads.Length)]; imageToSend = coins.Heads[_rng.Next(0, coins.Heads.Length)];
result = BetFlipGuess.Heads; result = BetFlipGuess.Heads;
} }
else else
{ {
imageToSend = coins.Tails[rng.Next(0, coins.Tails.Length)]; imageToSend = coins.Tails[_rng.Next(0, coins.Tails.Length)];
result = BetFlipGuess.Tails; result = BetFlipGuess.Tails;
} }
string str; string str;
if (guess == result) if (guess == result)
{ {
var toWin = (long)(amount * _config.BetFlip.Multiplier); var toWin = (long)(amount * Config.BetFlip.Multiplier);
str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.flip_guess(toWin + CurrencySign)); str = Format.Bold(ctx.User.ToString()) + " " + GetText(strs.flip_guess(toWin + CurrencySign));
await _cs.AddAsync(ctx.User, "Betflip Gamble", toWin, false, true); await _cs.AddAsync(ctx.User, "Betflip Gamble", toWin, false, true);
} }

View File

@@ -100,8 +100,8 @@ public partial class Gambling : GamblingModule<GamblingService>
[Cmd] [Cmd]
public async partial Task Timely() public async partial Task Timely()
{ {
var val = _config.Timely.Amount; var val = Config.Timely.Amount;
var period = _config.Timely.Cooldown; var period = Config.Timely.Cooldown;
if (val <= 0 || period <= 0) if (val <= 0 || period <= 0)
{ {
await ReplyErrorLocalizedAsync(strs.timely_none); await ReplyErrorLocalizedAsync(strs.timely_none);
@@ -473,7 +473,7 @@ public partial class Gambling : GamblingModule<GamblingService>
return; return;
} }
var br = new Betroll(_config.BetRoll); var br = new Betroll(Config.BetRoll);
var result = br.Roll(); var result = br.Roll();
@@ -617,7 +617,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|| (pick == RpsPick.Rock && nadekoPick == RpsPick.Scissors) || (pick == RpsPick.Rock && nadekoPick == RpsPick.Scissors)
|| (pick == RpsPick.Scissors && nadekoPick == RpsPick.Paper)) || (pick == RpsPick.Scissors && nadekoPick == RpsPick.Paper))
{ {
amount = (long)(amount * _config.BetFlip.Multiplier); amount = (long)(amount * Config.BetFlip.Multiplier);
await _cs.AddAsync(ctx.User.Id, "Rps-win", amount, true); await _cs.AddAsync(ctx.User.Id, "Rps-win", amount, true);
embed.WithOkColor(); embed.WithOkColor();
embed.AddField(GetText(strs.won), n(amount)); embed.AddField(GetText(strs.won), n(amount));

View File

@@ -6,11 +6,12 @@ namespace NadekoBot.Modules.Gambling.Services;
public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig> public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
{ {
private const string FilePath = "data/gambling.yml"; private const string FILE_PATH = "data/gambling.yml";
private static readonly TypedKey<GamblingConfig> changeKey = new("config.gambling.updated"); private static readonly TypedKey<GamblingConfig> _changeKey = new("config.gambling.updated");
public override string Name { get; } = "gambling"; public override string Name
=> "gambling";
private readonly IEnumerable<WaifuItemModel> antiGiftSeed = new[] private readonly IEnumerable<WaifuItemModel> _antiGiftSeed = new[]
{ {
new WaifuItemModel("🥀", 100, "WiltedRose", true), new WaifuItemModel("✂️", 1000, "Haircut", true), new WaifuItemModel("🥀", 100, "WiltedRose", true), new WaifuItemModel("✂️", 1000, "Haircut", true),
new WaifuItemModel("🧻", 10000, "ToiletPaper", true) new WaifuItemModel("🧻", 10000, "ToiletPaper", true)
@@ -18,7 +19,7 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub) public GamblingConfigService(IConfigSeria serializer, IPubSub pubSub)
: base(FilePath, serializer, pubSub, changeKey) : base(FILE_PATH, serializer, pubSub, _changeKey)
{ {
AddParsedProp("currency.name", gs => gs.Currency.Name, ConfigParsers.String, ConfigPrinters.ToString); AddParsedProp("currency.name", gs => gs.Currency.Name, ConfigParsers.String, ConfigPrinters.ToString);
AddParsedProp("currency.sign", gs => gs.Currency.Sign, ConfigParsers.String, ConfigPrinters.ToString); AddParsedProp("currency.sign", gs => gs.Currency.Sign, ConfigParsers.String, ConfigPrinters.ToString);
@@ -104,7 +105,7 @@ public sealed class GamblingConfigService : ConfigServiceBase<GamblingConfig>
if (data.Version < 2) if (data.Version < 2)
ModifyConfig(c => ModifyConfig(c =>
{ {
c.Waifu.Items = c.Waifu.Items.Concat(antiGiftSeed).ToList(); c.Waifu.Items = c.Waifu.Items.Concat(_antiGiftSeed).ToList();
c.Version = 2; c.Version = 2;
}); });

View File

@@ -5,14 +5,14 @@ namespace NadekoBot.Modules.Gambling.Common;
public abstract class GamblingModule<TService> : NadekoModule<TService> public abstract class GamblingModule<TService> : NadekoModule<TService>
{ {
protected GamblingConfig _config protected GamblingConfig Config
=> _lazyConfig.Value; => _lazyConfig.Value;
protected string CurrencySign protected string CurrencySign
=> _config.Currency.Sign; => Config.Currency.Sign;
protected string CurrencyName protected string CurrencyName
=> _config.Currency.Name; => Config.Currency.Name;
private readonly Lazy<GamblingConfig> _lazyConfig; private readonly Lazy<GamblingConfig> _lazyConfig;
@@ -22,15 +22,15 @@ public abstract class GamblingModule<TService> : NadekoModule<TService>
private async Task<bool> InternalCheckBet(long amount) private async Task<bool> InternalCheckBet(long amount)
{ {
if (amount < 1) return false; if (amount < 1) return false;
if (amount < _config.MinBet) if (amount < Config.MinBet)
{ {
await ReplyErrorLocalizedAsync(strs.min_bet_limit(Format.Bold(_config.MinBet.ToString()) + CurrencySign)); await ReplyErrorLocalizedAsync(strs.min_bet_limit(Format.Bold(Config.MinBet.ToString()) + CurrencySign));
return false; return false;
} }
if (_config.MaxBet > 0 && amount > _config.MaxBet) if (Config.MaxBet > 0 && amount > Config.MaxBet)
{ {
await ReplyErrorLocalizedAsync(strs.max_bet_limit(Format.Bold(_config.MaxBet.ToString()) + CurrencySign)); await ReplyErrorLocalizedAsync(strs.max_bet_limit(Format.Bold(Config.MaxBet.ToString()) + CurrencySign));
return false; return false;
} }

View File

@@ -9,11 +9,11 @@ public partial class Gambling
[Group] [Group]
public partial class PlantPickCommands : GamblingSubmodule<PlantPickService> public partial class PlantPickCommands : GamblingSubmodule<PlantPickService>
{ {
private readonly ILogCommandService logService; private readonly ILogCommandService _logService;
public PlantPickCommands(ILogCommandService logService, GamblingConfigService gss) public PlantPickCommands(ILogCommandService logService, GamblingConfigService gss)
: base(gss) : base(gss)
=> this.logService = logService; => this._logService = logService;
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
@@ -32,7 +32,7 @@ public partial class Gambling
if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages) if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages)
try try
{ {
logService.AddDeleteIgnore(ctx.Message.Id); _logService.AddDeleteIgnore(ctx.Message.Id);
await ctx.Message.DeleteAsync(); await ctx.Message.DeleteAsync();
} }
catch { } catch { }
@@ -49,7 +49,7 @@ public partial class Gambling
if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages) if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages)
{ {
logService.AddDeleteIgnore(ctx.Message.Id); _logService.AddDeleteIgnore(ctx.Message.Id);
await ctx.Message.DeleteAsync(); await ctx.Message.DeleteAsync();
} }
@@ -90,7 +90,7 @@ public partial class Gambling
return ctx.SendPaginatedConfirmAsync(page, return ctx.SendPaginatedConfirmAsync(page,
_ => _ =>
{ {
var items = enabledIn.Skip(page * 9).Take(9); var items = enabledIn.Skip(page * 9).Take(9).ToList();
if (!items.Any()) if (!items.Any())
return _eb.Create().WithErrorColor().WithDescription("-"); return _eb.Create().WithErrorColor().WithDescription("-");

View File

@@ -154,7 +154,7 @@ public partial class Gambling
{ {
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var x = uow.Set<ShopEntryItem>().Remove(item); uow.Set<ShopEntryItem>().Remove(item);
uow.SaveChanges(); uow.SaveChanges();
} }

View File

@@ -18,8 +18,8 @@ public partial class Gambling
[Group] [Group]
public partial class SlotCommands : GamblingSubmodule<GamblingService> public partial class SlotCommands : GamblingSubmodule<GamblingService>
{ {
private static long _totalBet; private static long totalBet;
private static long _totalPaidOut; private static long totalPaidOut;
private static readonly HashSet<ulong> _runningUsers = new(); private static readonly HashSet<ulong> _runningUsers = new();
@@ -28,7 +28,7 @@ public partial class Gambling
//thanks to judge for helping me with this //thanks to judge for helping me with this
private readonly IImageCache _images; private readonly IImageCache _images;
private FontProvider _fonts; private readonly FontProvider _fonts;
private readonly DbService _db; private readonly DbService _db;
public SlotCommands( public SlotCommands(
@@ -51,8 +51,8 @@ public partial class Gambling
public async partial Task SlotStats() public async partial Task SlotStats()
{ {
//i remembered to not be a moron //i remembered to not be a moron
var paid = _totalPaidOut; var paid = totalPaidOut;
var bet = _totalBet; var bet = totalBet;
if (bet <= 0) if (bet <= 0)
bet = 1; bet = 1;
@@ -120,8 +120,8 @@ public partial class Gambling
return; return;
} }
Interlocked.Add(ref _totalBet, amount); Interlocked.Add(ref totalBet, amount);
Interlocked.Add(ref _totalPaidOut, result.Won); Interlocked.Add(ref totalPaidOut, result.Won);
long ownedAmount; long ownedAmount;
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
@@ -130,12 +130,12 @@ public partial class Gambling
?? 0; ?? 0;
} }
using (var bgImage = Image.Load<Rgba32>(_images.SlotBackground, out var format)) using (var bgImage = Image.Load<Rgba32>(_images.SlotBackground, out _))
{ {
var numbers = new int[3]; var numbers = new int[3];
result.Rolls.CopyTo(numbers, 0); result.Rolls.CopyTo(numbers, 0);
Color fontColor = _config.Slots.CurrencyFontColor; Color fontColor = Config.Slots.CurrencyFontColor;
bgImage.Mutate(x => x.DrawText(new() bgImage.Mutate(x => x.DrawText(new()
{ {

View File

@@ -100,7 +100,7 @@ public class VoteRewardService : INService, IReadyExecutor
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, "Critical error loading discords.com vote rewards."); Log.Error(ex, "Critical error loading discords.com vote rewards");
} }
} }
} }

View File

@@ -39,9 +39,9 @@ public partial class Gambling
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async partial Task WaifuClaim(int amount, [Leftover] IUser target) public async partial Task WaifuClaim(int amount, [Leftover] IUser target)
{ {
if (amount < _config.Waifu.MinPrice) if (amount < Config.Waifu.MinPrice)
{ {
await ReplyErrorLocalizedAsync(strs.waifu_isnt_cheap(_config.Waifu.MinPrice + CurrencySign)); await ReplyErrorLocalizedAsync(strs.waifu_isnt_cheap(Config.Waifu.MinPrice + CurrencySign));
return; return;
} }
@@ -278,7 +278,7 @@ public partial class Gambling
[Priority(1)] [Priority(1)]
public async partial Task WaifuGift(int page = 1) public async partial Task WaifuGift(int page = 1)
{ {
if (--page < 0 || page > (_config.Waifu.Items.Count - 1) / 9) if (--page < 0 || page > (Config.Waifu.Items.Count - 1) / 9)
return; return;
var waifuItems = _service.GetWaifuItems(); var waifuItems = _service.GetWaifuItems();
@@ -294,7 +294,7 @@ public partial class Gambling
.ToList() .ToList()
.ForEach(x => embed.AddField( .ForEach(x => embed.AddField(
$"{(!x.Negative ? string.Empty : "\\💔")} {x.ItemEmoji} {x.Name}", $"{(!x.Negative ? string.Empty : "\\💔")} {x.ItemEmoji} {x.Name}",
Format.Bold(x.Price.ToString()) + _config.Currency.Sign, Format.Bold(x.Price.ToString()) + Config.Currency.Sign,
true)); true));
return embed; return embed;

View File

@@ -37,7 +37,7 @@ public partial class Gambling
var result = await _service.WheelOfFortuneSpinAsync(ctx.User.Id, amount); var result = await _service.WheelOfFortuneSpinAsync(ctx.User.Id, amount);
var wofMultipliers = _config.WheelOfFortune.Multipliers; var wofMultipliers = Config.WheelOfFortune.Multipliers;
await SendConfirmAsync(Format.Bold($@"{ctx.User.ToString()} won: {result.Amount + CurrencySign} await SendConfirmAsync(Format.Bold($@"{ctx.User.ToString()} won: {result.Amount + CurrencySign}
『{wofMultipliers[1]}』 『{wofMultipliers[0]}』 『{wofMultipliers[7]}』 『{wofMultipliers[1]}』 『{wofMultipliers[0]}』 『{wofMultipliers[7]}』

View File

@@ -28,7 +28,7 @@ public class Deck
{ 13, "King" } { 13, "King" }
}; };
private static Dictionary<string, Func<List<Card>, bool>> _handValues; private static Dictionary<string, Func<List<Card>, bool>> handValues;
public List<Card> CardPool { get; set; } public List<Card> CardPool { get; set; }
private readonly Random _r = new NadekoRandom(); private readonly Random _r = new NadekoRandom();
@@ -176,7 +176,7 @@ public class Deck
return HasStraightFlush(cards) && !IsRoyalFlush(cards); return HasStraightFlush(cards) && !IsRoyalFlush(cards);
} }
_handValues = new() handValues = new()
{ {
{ "Royal Flush", IsRoyalFlush }, { "Royal Flush", IsRoyalFlush },
{ "Straight Flush", IsStraightFlush }, { "Straight Flush", IsStraightFlush },
@@ -192,9 +192,10 @@ public class Deck
public static string GetHandValue(List<Card> cards) public static string GetHandValue(List<Card> cards)
{ {
if (_handValues is null) if (handValues is null)
InitHandValues(); InitHandValues();
foreach (var kvp in _handValues.Where(x => x.Value(cards))) return kvp.Key;
foreach (var kvp in handValues.Where(x => x.Value(cards))) return kvp.Key;
return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText()); return "High card " + (cards.FirstOrDefault(c => c.Number == 1)?.GetValueText() ?? cards.Max().GetValueText());
} }

View File

@@ -38,8 +38,8 @@ public sealed class AcrophobiaGame : IDisposable
public ImmutableArray<char> StartingLetters { get; private set; } public ImmutableArray<char> StartingLetters { get; private set; }
public Options Opts { get; } public Options Opts { get; }
private readonly Dictionary<AcrophobiaUser, int> submissions = new(); private readonly Dictionary<AcrophobiaUser, int> _submissions = new();
private readonly SemaphoreSlim locker = new(1, 1); private readonly SemaphoreSlim _locker = new(1, 1);
private readonly NadekoRandom _rng; private readonly NadekoRandom _rng;
private readonly HashSet<ulong> _usersWhoVoted = new(); private readonly HashSet<ulong> _usersWhoVoted = new();
@@ -55,37 +55,37 @@ public sealed class AcrophobiaGame : IDisposable
{ {
await OnStarted(this); await OnStarted(this);
await Task.Delay(Opts.SubmissionTime * 1000); await Task.Delay(Opts.SubmissionTime * 1000);
await locker.WaitAsync(); await _locker.WaitAsync();
try try
{ {
if (submissions.Count == 0) if (_submissions.Count == 0)
{ {
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
await OnVotingStarted(this, ImmutableArray.Create<KeyValuePair<AcrophobiaUser, int>>()); await OnVotingStarted(this, ImmutableArray.Create<KeyValuePair<AcrophobiaUser, int>>());
return; return;
} }
if (submissions.Count == 1) if (_submissions.Count == 1)
{ {
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
await OnVotingStarted(this, submissions.ToArray().ToImmutableArray()); await OnVotingStarted(this, _submissions.ToArray().ToImmutableArray());
return; return;
} }
CurrentPhase = Phase.Voting; CurrentPhase = Phase.Voting;
await OnVotingStarted(this, submissions.ToArray().ToImmutableArray()); await OnVotingStarted(this, _submissions.ToArray().ToImmutableArray());
} }
finally { locker.Release(); } finally { _locker.Release(); }
await Task.Delay(Opts.VoteTime * 1000); await Task.Delay(Opts.VoteTime * 1000);
await locker.WaitAsync(); await _locker.WaitAsync();
try try
{ {
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
await OnEnded(this, submissions.ToArray().ToImmutableArray()); await OnEnded(this, _submissions.ToArray().ToImmutableArray());
} }
finally { locker.Release(); } finally { _locker.Release(); }
} }
private void InitializeStartingLetters() private void InitializeStartingLetters()
@@ -107,26 +107,26 @@ public sealed class AcrophobiaGame : IDisposable
{ {
var user = new AcrophobiaUser(userId, userName, input.ToLowerInvariant().ToTitleCase()); var user = new AcrophobiaUser(userId, userName, input.ToLowerInvariant().ToTitleCase());
await locker.WaitAsync(); await _locker.WaitAsync();
try try
{ {
switch (CurrentPhase) switch (CurrentPhase)
{ {
case Phase.Submission: case Phase.Submission:
if (submissions.ContainsKey(user) || !IsValidAnswer(input)) if (_submissions.ContainsKey(user) || !IsValidAnswer(input))
break; break;
submissions.Add(user, 0); _submissions.Add(user, 0);
return true; return true;
case Phase.Voting: case Phase.Voting:
AcrophobiaUser toVoteFor; AcrophobiaUser toVoteFor;
if (!int.TryParse(input, out var index) if (!int.TryParse(input, out var index)
|| --index < 0 || --index < 0
|| index >= submissions.Count || index >= _submissions.Count
|| (toVoteFor = submissions.ToArray()[index].Key).UserId == user.UserId || (toVoteFor = _submissions.ToArray()[index].Key).UserId == user.UserId
|| !_usersWhoVoted.Add(userId)) || !_usersWhoVoted.Add(userId))
break; break;
++submissions[toVoteFor]; ++_submissions[toVoteFor];
_= Task.Run(() => OnUserVoted(userName)); _= Task.Run(() => OnUserVoted(userName));
return true; return true;
} }
@@ -135,7 +135,7 @@ public sealed class AcrophobiaGame : IDisposable
} }
finally finally
{ {
locker.Release(); _locker.Release();
} }
} }
@@ -169,8 +169,8 @@ public sealed class AcrophobiaGame : IDisposable
OnUserVoted = null; OnUserVoted = null;
OnVotingStarted = null; OnVotingStarted = null;
_usersWhoVoted.Clear(); _usersWhoVoted.Clear();
submissions.Clear(); _submissions.Clear();
locker.Dispose(); _locker.Dispose();
} }
public class Options : INadekoCommandOptions public class Options : INadekoCommandOptions

View File

@@ -31,19 +31,19 @@ public partial class Games
game.OnEnded += Game_OnEnded; game.OnEnded += Game_OnEnded;
game.OnVotingStarted += Game_OnVotingStarted; game.OnVotingStarted += Game_OnVotingStarted;
game.OnUserVoted += Game_OnUserVoted; game.OnUserVoted += Game_OnUserVoted;
_client.MessageReceived += _client_MessageReceived; _client.MessageReceived += ClientMessageReceived;
await game.Run(); await game.Run();
} }
finally finally
{ {
_client.MessageReceived -= _client_MessageReceived; _client.MessageReceived -= ClientMessageReceived;
_service.AcrophobiaGames.TryRemove(channel.Id, out game); _service.AcrophobiaGames.TryRemove(channel.Id, out game);
game.Dispose(); game?.Dispose();
} }
else else
await ReplyErrorLocalizedAsync(strs.acro_running); await ReplyErrorLocalizedAsync(strs.acro_running);
Task _client_MessageReceived(SocketMessage msg) Task ClientMessageReceived(SocketMessage msg)
{ {
if (msg.Channel.Id != ctx.Channel.Id) if (msg.Channel.Id != ctx.Channel.Id)
return Task.CompletedTask; return Task.CompletedTask;

View File

@@ -48,7 +48,7 @@ public class ChatterBotService : IEarlyBehavior
{ {
if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey)) if (!string.IsNullOrWhiteSpace(_creds.CleverbotApiKey))
return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory); return new OfficialCleverbotSession(_creds.CleverbotApiKey, _httpFactory);
return new CleverbotIOSession("GAh3wUfzDCpDpdpT", "RStKgqn7tcO9blbrv4KbXM8NDlb7H37C", _httpFactory); return new CleverbotIoSession("GAh3wUfzDCpDpdpT", "RStKgqn7tcO9blbrv4KbXM8NDlb7H37C", _httpFactory);
} }
public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot) public string PrepareMessage(IUserMessage msg, out IChatterBotSession cleverbot)

View File

@@ -7,13 +7,13 @@ public class CleverbotResponse
public string Output { get; set; } public string Output { get; set; }
} }
public class CleverbotIOCreateResponse public class CleverbotIoCreateResponse
{ {
public string Status { get; set; } public string Status { get; set; }
public string Nick { get; set; } public string Nick { get; set; }
} }
public class CleverbotIOAskResponse public class CleverbotIoAskResponse
{ {
public string Status { get; set; } public string Status { get; set; }
public string Response { get; set; } public string Response { get; set; }

View File

@@ -10,7 +10,7 @@ public class OfficialCleverbotSession : IChatterBotSession
private readonly string _apiKey; private readonly string _apiKey;
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private string _cs; private string cs;
public OfficialCleverbotSession(string apiKey, IHttpClientFactory factory) public OfficialCleverbotSession(string apiKey, IHttpClientFactory factory)
{ {
@@ -21,12 +21,12 @@ public class OfficialCleverbotSession : IChatterBotSession
public async Task<string> Think(string input) public async Task<string> Think(string input)
{ {
using var http = _httpFactory.CreateClient(); using var http = _httpFactory.CreateClient();
var dataString = await http.GetStringAsync(string.Format(QueryString, input, _cs ?? "")); var dataString = await http.GetStringAsync(string.Format(QueryString, input, cs ?? ""));
try try
{ {
var data = JsonConvert.DeserializeObject<CleverbotResponse>(dataString); var data = JsonConvert.DeserializeObject<CleverbotResponse>(dataString);
_cs = data?.Cs; cs = data?.Cs;
return data?.Output; return data?.Output;
} }
catch catch
@@ -37,7 +37,7 @@ public class OfficialCleverbotSession : IChatterBotSession
} }
} }
public class CleverbotIOSession : IChatterBotSession public class CleverbotIoSession : IChatterBotSession
{ {
private readonly string _key; private readonly string _key;
private readonly string _user; private readonly string _user;
@@ -47,7 +47,7 @@ public class CleverbotIOSession : IChatterBotSession
private readonly string _createEndpoint = "https://cleverbot.io/1.0/create"; private readonly string _createEndpoint = "https://cleverbot.io/1.0/create";
private readonly string _askEndpoint = "https://cleverbot.io/1.0/ask"; private readonly string _askEndpoint = "https://cleverbot.io/1.0/ask";
public CleverbotIOSession(string user, string key, IHttpClientFactory factory) public CleverbotIoSession(string user, string key, IHttpClientFactory factory)
{ {
_key = key; _key = key;
_user = user; _user = user;
@@ -58,14 +58,14 @@ public class CleverbotIOSession : IChatterBotSession
private async Task<string> GetNick() private async Task<string> GetNick()
{ {
using var _http = _httpFactory.CreateClient(); using var http = _httpFactory.CreateClient();
using var msg = new FormUrlEncodedContent(new[] using var msg = new FormUrlEncodedContent(new[]
{ {
new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key) new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key)
}); });
using var data = await _http.PostAsync(_createEndpoint, msg); using var data = await http.PostAsync(_createEndpoint, msg);
var str = await data.Content.ReadAsStringAsync(); var str = await data.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<CleverbotIOCreateResponse>(str); var obj = JsonConvert.DeserializeObject<CleverbotIoCreateResponse>(str);
if (obj.Status != "success") if (obj.Status != "success")
throw new OperationCanceledException(obj.Status); throw new OperationCanceledException(obj.Status);
@@ -74,15 +74,15 @@ public class CleverbotIOSession : IChatterBotSession
public async Task<string> Think(string input) public async Task<string> Think(string input)
{ {
using var _http = _httpFactory.CreateClient(); using var http = _httpFactory.CreateClient();
using var msg = new FormUrlEncodedContent(new[] using var msg = new FormUrlEncodedContent(new[]
{ {
new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key), new KeyValuePair<string, string>("user", _user), new KeyValuePair<string, string>("key", _key),
new KeyValuePair<string, string>("nick", await _nick), new KeyValuePair<string, string>("text", input) new KeyValuePair<string, string>("nick", await _nick), new KeyValuePair<string, string>("text", input)
}); });
using var data = await _http.PostAsync(_askEndpoint, msg); using var data = await http.PostAsync(_askEndpoint, msg);
var str = await data.Content.ReadAsStringAsync(); var str = await data.Content.ReadAsStringAsync();
var obj = JsonConvert.DeserializeObject<CleverbotIOAskResponse>(str); var obj = JsonConvert.DeserializeObject<CleverbotIoAskResponse>(str);
if (obj.Status != "success") if (obj.Status != "success")
throw new OperationCanceledException(obj.Status); throw new OperationCanceledException(obj.Status);

View File

@@ -6,12 +6,12 @@ namespace NadekoBot.Modules.Games.Services;
public sealed class GamesConfigService : ConfigServiceBase<GamesConfig> public sealed class GamesConfigService : ConfigServiceBase<GamesConfig>
{ {
private const string FilePath = "data/games.yml"; private const string FILE_PATH = "data/games.yml";
private static readonly TypedKey<GamesConfig> changeKey = new("config.games.updated"); private static readonly TypedKey<GamesConfig> _changeKey = new("config.games.updated");
public override string Name { get; } = "games"; public override string Name { get; } = "games";
public GamesConfigService(IConfigSeria serializer, IPubSub pubSub) public GamesConfigService(IConfigSeria serializer, IPubSub pubSub)
: base(FilePath, serializer, pubSub, changeKey) : base(FILE_PATH, serializer, pubSub, _changeKey)
{ {
AddParsedProp("trivia.min_win_req", AddParsedProp("trivia.min_win_req",
gs => gs.Trivia.MinimumWinReq, gs => gs.Trivia.MinimumWinReq,

View File

@@ -10,7 +10,7 @@ namespace NadekoBot.Modules.Games.Services;
public class GamesService : INService public class GamesService : INService
{ {
private const string TypingArticlesPath = "data/typing_articles3.json"; private const string TYPING_ARTICLES_PATH = "data/typing_articles3.json";
public ConcurrentDictionary<ulong, GirlRating> GirlRatings { get; } = new(); public ConcurrentDictionary<ulong, GirlRating> GirlRatings { get; } = new();
@@ -54,11 +54,11 @@ public class GamesService : INService
try try
{ {
TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(TypingArticlesPath)); TypingArticles = JsonConvert.DeserializeObject<List<TypingArticle>>(File.ReadAllText(TYPING_ARTICLES_PATH));
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Warning("Error while loading typing articles {0}", ex.ToString()); Log.Warning(ex, "Error while loading typing articles: {ErrorMessage}", ex.Message);
TypingArticles = new(); TypingArticles = new();
} }
} }
@@ -80,7 +80,7 @@ public class GamesService : INService
Text = text.SanitizeMentions(true) Text = text.SanitizeMentions(true)
}); });
File.WriteAllText(TypingArticlesPath, JsonConvert.SerializeObject(TypingArticles)); File.WriteAllText(TYPING_ARTICLES_PATH, JsonConvert.SerializeObject(TypingArticles));
} }
public string GetEightballResponse(ulong userId, string question) public string GetEightballResponse(ulong userId, string question)
@@ -90,7 +90,6 @@ public class GamesService : INService
e.Size = question.Length; e.Size = question.Length;
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12); e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
return EightBallResponses[_rng.Next(0, EightBallResponses.Count)]; return EightBallResponses[_rng.Next(0, EightBallResponses.Count)];
;
}); });
public TypingArticle RemoveTypingArticle(int index) public TypingArticle RemoveTypingArticle(int index)
@@ -102,7 +101,7 @@ public class GamesService : INService
var removed = articles[index]; var removed = articles[index];
TypingArticles.RemoveAt(index); TypingArticles.RemoveAt(index);
File.WriteAllText(TypingArticlesPath, JsonConvert.SerializeObject(articles)); File.WriteAllText(TYPING_ARTICLES_PATH, JsonConvert.SerializeObject(articles));
return removed; return removed;
} }

View File

@@ -15,11 +15,8 @@ public class GirlRating
public AsyncLazy<Stream> Stream { get; } public AsyncLazy<Stream> Stream { get; }
private readonly IImageCache _images; private readonly IImageCache _images;
private readonly IHttpClientFactory _httpFactory;
public GirlRating( public GirlRating(
IImageCache images, IImageCache images,
IHttpClientFactory factory,
double crazy, double crazy,
double hot, double hot,
int roll, int roll,
@@ -30,7 +27,6 @@ public class GirlRating
Hot = hot; Hot = hot;
Roll = roll; Roll = roll;
Advice = advice; // convenient to have it here, even though atm there are only few different ones. Advice = advice; // convenient to have it here, even though atm there are only few different ones.
_httpFactory = factory;
Stream = new(() => Stream = new(() =>
{ {

View File

@@ -5,7 +5,7 @@ namespace NadekoBot.Modules.Games.Hangman;
public sealed class DefaultHangmanSource : IHangmanSource public sealed class DefaultHangmanSource : IHangmanSource
{ {
private IReadOnlyDictionary<string, HangmanTerm[]> _terms = new Dictionary<string, HangmanTerm[]>(); private IReadOnlyDictionary<string, HangmanTerm[]> termsDict = new Dictionary<string, HangmanTerm[]>();
private readonly Random _rng; private readonly Random _rng;
public DefaultHangmanSource() public DefaultHangmanSource()
@@ -18,7 +18,7 @@ public sealed class DefaultHangmanSource : IHangmanSource
{ {
if (!Directory.Exists("data/hangman")) if (!Directory.Exists("data/hangman"))
{ {
Log.Error("Hangman game won't work. Folder 'data/hangman' is missing."); Log.Error("Hangman game won't work. Folder 'data/hangman' is missing");
return; return;
} }
@@ -31,16 +31,16 @@ public sealed class DefaultHangmanSource : IHangmanSource
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, "Loading {HangmanFile} failed.", file); Log.Error(ex, "Loading {HangmanFile} failed", file);
} }
_terms = qs; termsDict = qs;
Log.Information("Loaded {HangmanCategoryCount} hangman categories.", qs.Count); Log.Information("Loaded {HangmanCategoryCount} hangman categories", qs.Count);
} }
public IReadOnlyCollection<string> GetCategories() public IReadOnlyCollection<string> GetCategories()
=> _terms.Keys.ToList(); => termsDict.Keys.ToList();
public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term) public bool GetTerm(string? category, [NotNullWhen(true)] out HangmanTerm? term)
{ {
@@ -50,7 +50,7 @@ public sealed class DefaultHangmanSource : IHangmanSource
category = cats.ElementAt(_rng.Next(0, cats.Count)); category = cats.ElementAt(_rng.Next(0, cats.Count));
} }
if (_terms.TryGetValue(category, out var terms)) if (termsDict.TryGetValue(category, out var terms))
{ {
term = terms[_rng.Next(0, terms.Length)]; term = terms[_rng.Next(0, terms.Length)];
return true; return true;

View File

@@ -28,19 +28,19 @@ public partial class Games
.WithOkColor() .WithOkColor()
.AddField("Hangman", Draw(state)) .AddField("Hangman", Draw(state))
.AddField("Guess", Format.Code(state.Word)) .AddField("Guess", Format.Code(state.Word))
.WithFooter(state.missedLetters.Join(' ')); .WithFooter(state.MissedLetters.Join(' '));
if (state.Phase == HangmanGame.Phase.Ended && state.Failed) if (state.Phase == HangmanGame.Phase.Ended && state.Failed)
return eb.Create() return eb.Create()
.WithErrorColor() .WithErrorColor()
.AddField("Hangman", Draw(state)) .AddField("Hangman", Draw(state))
.AddField("Guess", Format.Code(state.Word)) .AddField("Guess", Format.Code(state.Word))
.WithFooter(state.missedLetters.Join(' ')); .WithFooter(state.MissedLetters.Join(' '));
return eb.Create() return eb.Create()
.WithOkColor() .WithOkColor()
.AddField("Hangman", Draw(state)) .AddField("Hangman", Draw(state))
.AddField("Guess", Format.Code(state.Word)) .AddField("Guess", Format.Code(state.Word))
.WithFooter(state.missedLetters.Join(' ')); .WithFooter(state.MissedLetters.Join(' '));
} }
[Cmd] [Cmd]

View File

@@ -104,7 +104,7 @@ public sealed class HangmanGame
Phase Phase, Phase Phase,
string Word, string Word,
GuessResult GuessResult, GuessResult GuessResult,
List<char> missedLetters, List<char> MissedLetters,
string ImageUrl) string ImageUrl)
{ {
public bool Failed public bool Failed

View File

@@ -54,7 +54,7 @@ public sealed class HangmanService : IHangmanService, ILateExecutor
{ {
lock (_locker) lock (_locker)
{ {
if (_hangmanGames.TryRemove(channelId, out var game)) return new(true); if (_hangmanGames.TryRemove(channelId, out _)) return new(true);
} }
return new(false); return new(false);

View File

@@ -13,8 +13,8 @@ public sealed class NunchiGame : IDisposable
Ended Ended
} }
private const int _killTimeout = 20 * 1000; private const int KILL_TIMEOUT = 20 * 1000;
private const int _nextRoundTimeout = 5 * 1000; private const int NEXT_ROUND_TIMEOUT = 5 * 1000;
public event Func<NunchiGame, Task> OnGameStarted; public event Func<NunchiGame, Task> OnGameStarted;
public event Func<NunchiGame, int, Task> OnRoundStarted; public event Func<NunchiGame, int, Task> OnRoundStarted;
@@ -26,19 +26,19 @@ public sealed class NunchiGame : IDisposable
public Phase CurrentPhase { get; private set; } = Phase.Joining; public Phase CurrentPhase { get; private set; } = Phase.Joining;
public ImmutableArray<(ulong Id, string Name)> Participants public ImmutableArray<(ulong Id, string Name)> Participants
=> _participants.ToImmutableArray(); => participants.ToImmutableArray();
public int ParticipantCount public int ParticipantCount
=> _participants.Count; => participants.Count;
private readonly SemaphoreSlim _locker = new(1, 1); private readonly SemaphoreSlim _locker = new(1, 1);
private HashSet<(ulong Id, string Name)> _participants = new(); private HashSet<(ulong Id, string Name)> participants = new();
private readonly HashSet<(ulong Id, string Name)> _passed = new(); private readonly HashSet<(ulong Id, string Name)> _passed = new();
private Timer _killTimer; private Timer killTimer;
public NunchiGame(ulong creatorId, string creatorName) public NunchiGame(ulong creatorId, string creatorName)
=> _participants.Add((creatorId, creatorName)); => participants.Add((creatorId, creatorName));
public async Task<bool> Join(ulong userId, string userName) public async Task<bool> Join(ulong userId, string userName)
{ {
@@ -48,7 +48,7 @@ public sealed class NunchiGame : IDisposable
if (CurrentPhase != Phase.Joining) if (CurrentPhase != Phase.Joining)
return false; return false;
return _participants.Add((userId, userName)); return participants.Add((userId, userName));
} }
finally { _locker.Release(); } finally { _locker.Release(); }
} }
@@ -60,13 +60,13 @@ public sealed class NunchiGame : IDisposable
await _locker.WaitAsync(); await _locker.WaitAsync();
try try
{ {
if (_participants.Count < 3) if (participants.Count < 3)
{ {
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
return false; return false;
} }
_killTimer = new(async _ => killTimer = new(async _ =>
{ {
await _locker.WaitAsync(); await _locker.WaitAsync();
try try
@@ -75,14 +75,14 @@ public sealed class NunchiGame : IDisposable
return; return;
//if some players took too long to type a number, boot them all out and start a new round //if some players took too long to type a number, boot them all out and start a new round
_participants = new HashSet<(ulong, string)>(_passed); participants = new HashSet<(ulong, string)>(_passed);
EndRound(); EndRound();
} }
finally { _locker.Release(); } finally { _locker.Release(); }
}, },
null, null,
_killTimeout, KILL_TIMEOUT,
_killTimeout); KILL_TIMEOUT);
CurrentPhase = Phase.Playing; CurrentPhase = Phase.Playing;
_= OnGameStarted?.Invoke(this); _= OnGameStarted?.Invoke(this);
@@ -105,7 +105,7 @@ public sealed class NunchiGame : IDisposable
// if the user is not a member of the race, // if the user is not a member of the race,
// or he already successfully typed the number // or he already successfully typed the number
// ignore the input // ignore the input
if (!_participants.Contains(userTuple) || !_passed.Add(userTuple)) if (!participants.Contains(userTuple) || !_passed.Add(userTuple))
return; return;
//if the number is correct //if the number is correct
@@ -113,20 +113,20 @@ public sealed class NunchiGame : IDisposable
{ {
//increment current number //increment current number
++CurrentNumber; ++CurrentNumber;
if (_passed.Count == _participants.Count - 1) if (_passed.Count == participants.Count - 1)
{ {
// if only n players are left, and n - 1 type the correct number, round is over // if only n players are left, and n - 1 type the correct number, round is over
// if only 2 players are left, game is over // if only 2 players are left, game is over
if (_participants.Count == 2) if (participants.Count == 2)
{ {
_killTimer.Change(Timeout.Infinite, Timeout.Infinite); killTimer.Change(Timeout.Infinite, Timeout.Infinite);
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
_= OnGameEnded?.Invoke(this, userTuple.Name); _= OnGameEnded?.Invoke(this, userTuple.Name);
} }
else // else just start the new round without the user who was the last else // else just start the new round without the user who was the last
{ {
var failure = _participants.Except(_passed).First(); var failure = participants.Except(_passed).First();
OnUserGuessed?.Invoke(this); OnUserGuessed?.Invoke(this);
EndRound(failure); EndRound(failure);
@@ -148,25 +148,25 @@ public sealed class NunchiGame : IDisposable
private void EndRound((ulong, string)? failure = null) private void EndRound((ulong, string)? failure = null)
{ {
_killTimer.Change(_killTimeout, _killTimeout); killTimer.Change(KILL_TIMEOUT, KILL_TIMEOUT);
CurrentNumber = new NadekoRandom().Next(0, 100); // reset the counter CurrentNumber = new NadekoRandom().Next(0, 100); // reset the counter
_passed.Clear(); // reset all users who passed (new round starts) _passed.Clear(); // reset all users who passed (new round starts)
if (failure is not null) if (failure is not null)
_participants.Remove(failure.Value); // remove the dude who failed from the list of players participants.Remove(failure.Value); // remove the dude who failed from the list of players
var __ = OnRoundEnded?.Invoke(this, failure); var __ = OnRoundEnded?.Invoke(this, failure);
if (_participants.Count <= 1) // means we have a winner or everyone was booted out if (participants.Count <= 1) // means we have a winner or everyone was booted out
{ {
_killTimer.Change(Timeout.Infinite, Timeout.Infinite); killTimer.Change(Timeout.Infinite, Timeout.Infinite);
CurrentPhase = Phase.Ended; CurrentPhase = Phase.Ended;
_= OnGameEnded?.Invoke(this, _participants.Count > 0 ? _participants.First().Name : null); _= OnGameEnded?.Invoke(this, participants.Count > 0 ? participants.First().Name : null);
return; return;
} }
CurrentPhase = Phase.WaitingForNextRound; CurrentPhase = Phase.WaitingForNextRound;
var throwawayDelay = Task.Run(async () => var throwawayDelay = Task.Run(async () =>
{ {
await Task.Delay(_nextRoundTimeout); await Task.Delay(NEXT_ROUND_TIMEOUT);
CurrentPhase = Phase.Playing; CurrentPhase = Phase.Playing;
var ___ = OnRoundStarted?.Invoke(this, CurrentNumber); var ___ = OnRoundStarted?.Invoke(this, CurrentNumber);
}); });

View File

@@ -38,12 +38,12 @@ public partial class Games
try { await ConfirmLocalizedAsync(strs.nunchi_created); } try { await ConfirmLocalizedAsync(strs.nunchi_created); }
catch { } catch { }
nunchi.OnGameEnded += Nunchi_OnGameEnded; nunchi.OnGameEnded += NunchiOnGameEnded;
//nunchi.OnGameStarted += Nunchi_OnGameStarted; //nunchi.OnGameStarted += Nunchi_OnGameStarted;
nunchi.OnRoundEnded += Nunchi_OnRoundEnded; nunchi.OnRoundEnded += Nunchi_OnRoundEnded;
nunchi.OnUserGuessed += Nunchi_OnUserGuessed; nunchi.OnUserGuessed += Nunchi_OnUserGuessed;
nunchi.OnRoundStarted += Nunchi_OnRoundStarted; nunchi.OnRoundStarted += Nunchi_OnRoundStarted;
_client.MessageReceived += _client_MessageReceived; _client.MessageReceived += ClientMessageReceived;
var success = await nunchi.Initialize(); var success = await nunchi.Initialize();
if (!success) if (!success)
@@ -53,7 +53,7 @@ public partial class Games
await ConfirmLocalizedAsync(strs.nunchi_failed_to_start); await ConfirmLocalizedAsync(strs.nunchi_failed_to_start);
} }
Task _client_MessageReceived(SocketMessage arg) Task ClientMessageReceived(SocketMessage arg)
{ {
_= Task.Run(async () => _= Task.Run(async () =>
{ {
@@ -73,11 +73,11 @@ public partial class Games
return Task.CompletedTask; return Task.CompletedTask;
} }
Task Nunchi_OnGameEnded(NunchiGame arg1, string arg2) Task NunchiOnGameEnded(NunchiGame arg1, string arg2)
{ {
if (_service.NunchiGames.TryRemove(ctx.Guild.Id, out var game)) if (_service.NunchiGames.TryRemove(ctx.Guild.Id, out var game))
{ {
_client.MessageReceived -= _client_MessageReceived; _client.MessageReceived -= ClientMessageReceived;
game.Dispose(); game.Dispose();
} }

View File

@@ -90,8 +90,8 @@ public partial class Games
for (var i = 0; i < stats.Length; i++) for (var i = 0; i < stats.Length; i++)
{ {
var (Index, votes, Text) = stats[i]; var (index, votes, text) = stats[i];
sb.AppendLine(GetText(strs.poll_result(Index + 1, Format.Bold(Text), Format.Bold(votes.ToString())))); sb.AppendLine(GetText(strs.poll_result(index + 1, Format.Bold(text), Format.Bold(votes.ToString()))));
} }
return eb.WithDescription(sb.ToString()) return eb.WithDescription(sb.ToString())

View File

@@ -10,19 +10,19 @@ public class TicTacToe
private readonly ITextChannel _channel; private readonly ITextChannel _channel;
private readonly IGuildUser[] _users; private readonly IGuildUser[] _users;
private readonly int?[,] _state; private readonly int?[,] _state;
private Phase _phase; private Phase phase;
private int _curUserIndex; private int curUserIndex;
private readonly SemaphoreSlim _moveLock; private readonly SemaphoreSlim _moveLock;
private IGuildUser _winner; private IGuildUser winner;
private readonly string[] _numbers = private readonly string[] _numbers =
{ {
":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:"
}; };
private IUserMessage _previousMessage; private IUserMessage previousMessage;
private Timer _timeoutTimer; private Timer timeoutTimer;
private readonly IBotStrings _strings; private readonly IBotStrings _strings;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly Options _options; private readonly Options _options;
@@ -45,7 +45,7 @@ public class TicTacToe
_users = new[] { firstUser, null }; _users = new[] { firstUser, null };
_state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null } }; _state = new int?[,] { { null, null, null }, { null, null, null }, { null, null, null } };
_phase = Phase.Starting; phase = Phase.Starting;
_moveLock = new(1, 1); _moveLock = new(1, 1);
} }
@@ -81,16 +81,16 @@ public class TicTacToe
if (!string.IsNullOrWhiteSpace(title)) if (!string.IsNullOrWhiteSpace(title))
embed.WithTitle(title); embed.WithTitle(title);
if (_winner is null) if (winner is null)
{ {
if (_phase == Phase.Ended) if (phase == Phase.Ended)
embed.WithFooter(GetText(strs.ttt_no_moves)); embed.WithFooter(GetText(strs.ttt_no_moves));
else else
embed.WithFooter(GetText(strs.ttt_users_move(_users[_curUserIndex]))); embed.WithFooter(GetText(strs.ttt_users_move(_users[curUserIndex])));
} }
else else
{ {
embed.WithFooter(GetText(strs.ttt_has_won(_winner))); embed.WithFooter(GetText(strs.ttt_has_won(winner)));
} }
return embed; return embed;
@@ -115,7 +115,7 @@ public class TicTacToe
public async Task Start(IGuildUser user) public async Task Start(IGuildUser user)
{ {
if (_phase is Phase.Started or Phase.Ended) if (phase is Phase.Started or Phase.Ended)
{ {
await _channel.SendErrorAsync(_eb, user.Mention + GetText(strs.ttt_already_running)); await _channel.SendErrorAsync(_eb, user.Mention + GetText(strs.ttt_already_running));
return; return;
@@ -129,21 +129,21 @@ public class TicTacToe
_users[1] = user; _users[1] = user;
_phase = Phase.Started; phase = Phase.Started;
_timeoutTimer = new(async _ => timeoutTimer = new(async _ =>
{ {
await _moveLock.WaitAsync(); await _moveLock.WaitAsync();
try try
{ {
if (_phase == Phase.Ended) if (phase == Phase.Ended)
return; return;
_phase = Phase.Ended; phase = Phase.Ended;
if (_users[1] is not null) if (_users[1] is not null)
{ {
_winner = _users[_curUserIndex ^= 1]; winner = _users[curUserIndex ^= 1];
var del = _previousMessage?.DeleteAsync(); var del = previousMessage?.DeleteAsync();
try try
{ {
await _channel.EmbedAsync(GetEmbed(GetText(strs.ttt_time_expired))); await _channel.EmbedAsync(GetEmbed(GetText(strs.ttt_time_expired)));
@@ -168,7 +168,7 @@ public class TicTacToe
_client.MessageReceived += Client_MessageReceived; _client.MessageReceived += Client_MessageReceived;
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText(strs.game_started))); previousMessage = await _channel.EmbedAsync(GetEmbed(GetText(strs.game_started)));
} }
private bool IsDraw() private bool IsDraw()
@@ -187,8 +187,8 @@ public class TicTacToe
await _moveLock.WaitAsync(); await _moveLock.WaitAsync();
try try
{ {
var curUser = _users[_curUserIndex]; var curUser = _users[curUserIndex];
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id) if (phase == Phase.Ended || msg.Author?.Id != curUser.Id)
return; return;
if (int.TryParse(msg.Content, out var index) if (int.TryParse(msg.Content, out var index)
@@ -196,69 +196,69 @@ public class TicTacToe
&& index <= 9 && index <= 9
&& _state[index / 3, index % 3] is null) && _state[index / 3, index % 3] is null)
{ {
_state[index / 3, index % 3] = _curUserIndex; _state[index / 3, index % 3] = curUserIndex;
// i'm lazy // i'm lazy
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2]) if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
{ {
_state[index / 3, 0] = _curUserIndex + 2; _state[index / 3, 0] = curUserIndex + 2;
_state[index / 3, 1] = _curUserIndex + 2; _state[index / 3, 1] = curUserIndex + 2;
_state[index / 3, 2] = _curUserIndex + 2; _state[index / 3, 2] = curUserIndex + 2;
_phase = Phase.Ended; phase = Phase.Ended;
} }
else if (_state[0, index % 3] == _state[1, index % 3] else if (_state[0, index % 3] == _state[1, index % 3]
&& _state[1, index % 3] == _state[2, index % 3]) && _state[1, index % 3] == _state[2, index % 3])
{ {
_state[0, index % 3] = _curUserIndex + 2; _state[0, index % 3] = curUserIndex + 2;
_state[1, index % 3] = _curUserIndex + 2; _state[1, index % 3] = curUserIndex + 2;
_state[2, index % 3] = _curUserIndex + 2; _state[2, index % 3] = curUserIndex + 2;
_phase = Phase.Ended; phase = Phase.Ended;
} }
else if (_curUserIndex == _state[0, 0] else if (curUserIndex == _state[0, 0]
&& _state[0, 0] == _state[1, 1] && _state[0, 0] == _state[1, 1]
&& _state[1, 1] == _state[2, 2]) && _state[1, 1] == _state[2, 2])
{ {
_state[0, 0] = _curUserIndex + 2; _state[0, 0] = curUserIndex + 2;
_state[1, 1] = _curUserIndex + 2; _state[1, 1] = curUserIndex + 2;
_state[2, 2] = _curUserIndex + 2; _state[2, 2] = curUserIndex + 2;
_phase = Phase.Ended; phase = Phase.Ended;
} }
else if (_curUserIndex == _state[0, 2] else if (curUserIndex == _state[0, 2]
&& _state[0, 2] == _state[1, 1] && _state[0, 2] == _state[1, 1]
&& _state[1, 1] == _state[2, 0]) && _state[1, 1] == _state[2, 0])
{ {
_state[0, 2] = _curUserIndex + 2; _state[0, 2] = curUserIndex + 2;
_state[1, 1] = _curUserIndex + 2; _state[1, 1] = curUserIndex + 2;
_state[2, 0] = _curUserIndex + 2; _state[2, 0] = curUserIndex + 2;
_phase = Phase.Ended; phase = Phase.Ended;
} }
var reason = string.Empty; var reason = string.Empty;
if (_phase == Phase.Ended) // if user won, stop receiving moves if (phase == Phase.Ended) // if user won, stop receiving moves
{ {
reason = GetText(strs.ttt_matched_three); reason = GetText(strs.ttt_matched_three);
_winner = _users[_curUserIndex]; winner = _users[curUserIndex];
_client.MessageReceived -= Client_MessageReceived; _client.MessageReceived -= Client_MessageReceived;
OnEnded?.Invoke(this); OnEnded?.Invoke(this);
} }
else if (IsDraw()) else if (IsDraw())
{ {
reason = GetText(strs.ttt_a_draw); reason = GetText(strs.ttt_a_draw);
_phase = Phase.Ended; phase = Phase.Ended;
_client.MessageReceived -= Client_MessageReceived; _client.MessageReceived -= Client_MessageReceived;
OnEnded?.Invoke(this); OnEnded?.Invoke(this);
} }
var sendstate = Task.Run(async () => _ = Task.Run(async () =>
{ {
var del1 = msg.DeleteAsync(); var del1 = msg.DeleteAsync();
var del2 = _previousMessage?.DeleteAsync(); var del2 = previousMessage?.DeleteAsync();
try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); }
catch { } catch { }
try { await del1; } try { await del1; }
@@ -270,9 +270,9 @@ public class TicTacToe
} }
catch { } catch { }
}); });
_curUserIndex ^= 1; curUserIndex ^= 1;
_timeoutTimer.Change(_options.TurnTimer * 1000, Timeout.Infinite); timeoutTimer.Change(_options.TurnTimer * 1000, Timeout.Infinite);
} }
} }
finally finally

View File

@@ -6,10 +6,10 @@ namespace NadekoBot.Modules.Games.Common.Trivia;
public class TriviaQuestion public class TriviaQuestion
{ {
public const int maxStringLength = 22; public const int MAX_STRING_LENGTH = 22;
//represents the min size to judge levDistance with //represents the min size to judge levDistance with
private static readonly HashSet<Tuple<int, int>> strictness = new() private static readonly HashSet<Tuple<int, int>> _strictness = new()
{ {
new(9, 0), new(14, 1), new(19, 2), new(22, 3) new(9, 0), new(14, 1), new(19, 2), new(22, 3)
}; };
@@ -56,7 +56,7 @@ public class TriviaQuestion
private static bool JudgeGuess(int guessLength, int answerLength, int levDistance) private static bool JudgeGuess(int guessLength, int answerLength, int levDistance)
{ {
foreach (var level in strictness) foreach (var level in _strictness)
if (guessLength <= level.Item1 || answerLength <= level.Item1) if (guessLength <= level.Item1 || answerLength <= level.Item1)
{ {
if (levDistance <= level.Item2) if (levDistance <= level.Item2)
@@ -78,7 +78,7 @@ public class TriviaQuestion
str = Regex.Replace(str, "^\\s+", ""); str = Regex.Replace(str, "^\\s+", "");
str = Regex.Replace(str, "\\s+$", ""); str = Regex.Replace(str, "\\s+$", "");
//Trim the really long answers //Trim the really long answers
str = str.Length <= maxStringLength ? str : str[..maxStringLength]; str = str.Length <= MAX_STRING_LENGTH ? str : str[..MAX_STRING_LENGTH];
return str; return str;
} }

View File

@@ -10,14 +10,14 @@ public class TriviaQuestionPool
=> _cache.LocalData.PokemonMap; => _cache.LocalData.PokemonMap;
private readonly IDataCache _cache; private readonly IDataCache _cache;
private readonly int maxPokemonId; private readonly int _maxPokemonId;
private readonly NadekoRandom _rng = new(); private readonly NadekoRandom _rng = new();
public TriviaQuestionPool(IDataCache cache) public TriviaQuestionPool(IDataCache cache)
{ {
_cache = cache; _cache = cache;
maxPokemonId = 721; //xd _maxPokemonId = 721; //xd
} }
public TriviaQuestion GetRandomQuestion(HashSet<TriviaQuestion> exclude, bool isPokemon) public TriviaQuestion GetRandomQuestion(HashSet<TriviaQuestion> exclude, bool isPokemon)
@@ -27,7 +27,7 @@ public class TriviaQuestionPool
if (isPokemon) if (isPokemon)
{ {
var num = _rng.Next(1, maxPokemonId + 1); var num = _rng.Next(1, _maxPokemonId + 1);
return new("Who's That Pokémon?", return new("Who's That Pokémon?",
Map[num].ToTitleCase(), Map[num].ToTitleCase(),
"Pokemon", "Pokemon",
@@ -36,7 +36,15 @@ public class TriviaQuestionPool
} }
TriviaQuestion randomQuestion; TriviaQuestion randomQuestion;
while (exclude.Contains(randomQuestion = Pool[_rng.Next(0, Pool.Length)])) ; while (exclude.Contains(randomQuestion = Pool[_rng.Next(0, Pool.Length)]))
{
// if too many questions are excluded, clear the exclusion list and start over
if (exclude.Count > Pool.Length / 10 * 9)
{
exclude.Clear();
break;
}
}
return randomQuestion; return randomQuestion;
} }

View File

@@ -16,15 +16,15 @@ public sealed partial class Music : NadekoModule<IMusicService>
Q = 2, Queue = 2, Playlist = 2, Pl = 2 Q = 2, Queue = 2, Playlist = 2, Pl = 2
} }
public const string MusicIconUrl = "http://i.imgur.com/nhKS3PT.png"; public const string MUSIC_ICON_URL = "http://i.imgur.com/nhKS3PT.png";
private const int LQ_ITEMS_PER_PAGE = 9; private const int LQ_ITEMS_PER_PAGE = 9;
private static readonly SemaphoreSlim voiceChannelLock = new(1, 1); private static readonly SemaphoreSlim _voiceChannelLock = new(1, 1);
private readonly ILogCommandService _logService; private readonly ILogCommandService _logService;
public Music(ILogCommandService _logService) public Music(ILogCommandService logService)
=> this._logService = _logService; => _logService = logService;
private async Task<bool> ValidateAsync() private async Task<bool> ValidateAsync()
{ {
@@ -50,7 +50,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null) private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null)
{ {
botUser ??= await ctx.Guild.GetCurrentUserAsync(); botUser ??= await ctx.Guild.GetCurrentUserAsync();
await voiceChannelLock.WaitAsync(); await _voiceChannelLock.WaitAsync();
try try
{ {
if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _)) if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _))
@@ -58,7 +58,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
} }
finally finally
{ {
voiceChannelLock.Release(); _voiceChannelLock.Release();
} }
} }
@@ -111,7 +111,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
{ {
var embed = _eb.Create() var embed = _eb.Create()
.WithOkColor() .WithOkColor()
.WithAuthor(GetText(strs.queued_song) + " #" + (index + 1), MusicIconUrl) .WithAuthor(GetText(strs.queued_song) + " #" + (index + 1), MUSIC_ICON_URL)
.WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ") .WithDescription($"{trackInfo.PrettyName()}\n{GetText(strs.queue)} ")
.WithFooter(trackInfo.Platform.ToString()); .WithFooter(trackInfo.Platform.ToString());
@@ -272,7 +272,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
return; return;
} }
IEmbedBuilder printAction(int curPage) IEmbedBuilder PrintAction(int curPage)
{ {
var desc = string.Empty; var desc = string.Empty;
var current = mp.GetCurrentTrack(out var currentIndex); var current = mp.GetCurrentTrack(out var currentIndex);
@@ -317,7 +317,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
var embed = _eb.Create() var embed = _eb.Create()
.WithAuthor(GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)), .WithAuthor(GetText(strs.player_queue(curPage + 1, (tracks.Count / LQ_ITEMS_PER_PAGE) + 1)),
MusicIconUrl) MUSIC_ICON_URL)
.WithDescription(desc) .WithDescription(desc)
.WithFooter($" {mp.PrettyVolume()} | 🎶 {tracks.Count} | ⌛ {mp.PrettyTotalTime()} ") .WithFooter($" {mp.PrettyVolume()} | 🎶 {tracks.Count} | ⌛ {mp.PrettyTotalTime()} ")
.WithOkColor(); .WithOkColor();
@@ -325,7 +325,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
return embed; return embed;
} }
await ctx.SendPaginatedConfirmAsync(page, printAction, tracks.Count, LQ_ITEMS_PER_PAGE, false); await ctx.SendPaginatedConfirmAsync(page, PrintAction, tracks.Count, LQ_ITEMS_PER_PAGE, false);
} }
// search // search
@@ -409,7 +409,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
} }
var embed = _eb.Create() var embed = _eb.Create()
.WithAuthor(GetText(strs.removed_song) + " #" + index, MusicIconUrl) .WithAuthor(GetText(strs.removed_song) + " #" + index, MUSIC_ICON_URL)
.WithDescription(song.PrettyName()) .WithDescription(song.PrettyName())
.WithFooter(song.PrettyInfo()) .WithFooter(song.PrettyInfo())
.WithErrorColor(); .WithErrorColor();
@@ -578,7 +578,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
var embed = _eb.Create() var embed = _eb.Create()
.WithTitle(track.Title.TrimTo(65)) .WithTitle(track.Title.TrimTo(65))
.WithAuthor(GetText(strs.song_moved), MusicIconUrl) .WithAuthor(GetText(strs.song_moved), MUSIC_ICON_URL)
.AddField(GetText(strs.from_position), $"#{from + 1}", true) .AddField(GetText(strs.from_position), $"#{from + 1}", true)
.AddField(GetText(strs.to_position), $"#{to + 1}", true) .AddField(GetText(strs.to_position), $"#{to + 1}", true)
.WithOkColor(); .WithOkColor();
@@ -667,7 +667,7 @@ public sealed partial class Music : NadekoModule<IMusicService>
var embed = _eb.Create() var embed = _eb.Create()
.WithOkColor() .WithOkColor()
.WithAuthor(GetText(strs.now_playing), MusicIconUrl) .WithAuthor(GetText(strs.now_playing), MUSIC_ICON_URL)
.WithDescription(currentTrack.PrettyName()) .WithDescription(currentTrack.PrettyName())
.WithThumbnailUrl(currentTrack.Thumbnail) .WithThumbnailUrl(currentTrack.Thumbnail)
.WithFooter( .WithFooter(

View File

@@ -23,7 +23,7 @@ public sealed partial class Music
private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null) private async Task EnsureBotInVoiceChannelAsync(ulong voiceChannelId, IGuildUser botUser = null)
{ {
botUser ??= await ctx.Guild.GetCurrentUserAsync(); botUser ??= await ctx.Guild.GetCurrentUserAsync();
await voiceChannelLock.WaitAsync(); await _voiceChannelLock.WaitAsync();
try try
{ {
if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _)) if (botUser.VoiceChannel?.Id is null || !_service.TryGetMusicPlayer(ctx.Guild.Id, out _))
@@ -31,7 +31,7 @@ public sealed partial class Music
} }
finally finally
{ {
voiceChannelLock.Release(); _voiceChannelLock.Release();
} }
} }
@@ -50,7 +50,7 @@ public sealed partial class Music
} }
var embed = _eb.Create(ctx) var embed = _eb.Create(ctx)
.WithAuthor(GetText(strs.playlists_page(num)), MusicIconUrl) .WithAuthor(GetText(strs.playlists_page(num)), MUSIC_ICON_URL)
.WithDescription(string.Join("\n", .WithDescription(string.Join("\n",
playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count))))) playlists.Select(r => GetText(strs.playlists(r.Id, r.Name, r.Author, r.Songs.Count)))))
.WithOkColor(); .WithOkColor();

View File

@@ -189,7 +189,7 @@ public sealed class MusicService : IMusicService
_ = lastFinishedMessage?.DeleteAsync(); _ = lastFinishedMessage?.DeleteAsync();
var embed = _eb.Create() var embed = _eb.Create()
.WithOkColor() .WithOkColor()
.WithAuthor(GetText(guildId, strs.finished_song), Music.MusicIconUrl) .WithAuthor(GetText(guildId, strs.finished_song), Music.MUSIC_ICON_URL)
.WithDescription(trackInfo.PrettyName()) .WithDescription(trackInfo.PrettyName())
.WithFooter(trackInfo.PrettyTotalTime()); .WithFooter(trackInfo.PrettyTotalTime());
@@ -205,7 +205,7 @@ public sealed class MusicService : IMusicService
_ = lastPlayingMessage?.DeleteAsync(); _ = lastPlayingMessage?.DeleteAsync();
var embed = _eb.Create() var embed = _eb.Create()
.WithOkColor() .WithOkColor()
.WithAuthor(GetText(guildId, strs.playing_song(index + 1)), Music.MusicIconUrl) .WithAuthor(GetText(guildId, strs.playing_song(index + 1)), Music.MUSIC_ICON_URL)
.WithDescription(trackInfo.PrettyName()) .WithDescription(trackInfo.PrettyName())
.WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}"); .WithFooter($"{mp.PrettyVolume()} | {trackInfo.PrettyInfo()}");

View File

@@ -5,7 +5,7 @@ namespace NadekoBot.Modules.Music.Common;
public sealed class MultimediaTimer : IDisposable public sealed class MultimediaTimer : IDisposable
{ {
private LpTimeProcDelegate _lpTimeProc; private LpTimeProcDelegate lpTimeProc;
private readonly uint _eventId; private readonly uint _eventId;
private readonly Action<object> _callback; private readonly Action<object> _callback;
private readonly object _state; private readonly object _state;
@@ -18,8 +18,8 @@ public sealed class MultimediaTimer : IDisposable
_callback = callback; _callback = callback;
_state = state; _state = state;
_lpTimeProc = CallbackInternal; lpTimeProc = CallbackInternal;
_eventId = timeSetEvent((uint)period, 1, _lpTimeProc, 0, TimerMode.Periodic); _eventId = timeSetEvent((uint)period, 1, lpTimeProc, 0, TimerMode.Periodic);
} }
/// <summary> /// <summary>
@@ -58,13 +58,13 @@ public sealed class MultimediaTimer : IDisposable
/// <summary> /// <summary>
/// The timeKillEvent function cancels a specified timer event. /// The timeKillEvent function cancels a specified timer event.
/// </summary> /// </summary>
/// <param name="uTimerID"> /// <param name="uTimerId">
/// Identifier of the timer event to cancel. /// Identifier of the timer event to cancel.
/// This identifier was returned by the timeSetEvent function when the timer event was set up. /// This identifier was returned by the timeSetEvent function when the timer event was set up.
/// </param> /// </param>
/// <returns>Returns TIMERR_NOERROR if successful or MMSYSERR_INVALPARAM if the specified timer event does not exist.</returns> /// <returns>Returns TIMERR_NOERROR if successful or MMSYSERR_INVALPARAM if the specified timer event does not exist.</returns>
[DllImport("Winmm.dll")] [DllImport("Winmm.dll")]
private static extern int timeKillEvent(uint uTimerID); private static extern int timeKillEvent(uint uTimerId);
private void CallbackInternal( private void CallbackInternal(
uint uTimerId, uint uTimerId,
@@ -76,12 +76,12 @@ public sealed class MultimediaTimer : IDisposable
public void Dispose() public void Dispose()
{ {
_lpTimeProc = default; lpTimeProc = default;
timeKillEvent(_eventId); timeKillEvent(_eventId);
} }
private delegate void LpTimeProcDelegate( private delegate void LpTimeProcDelegate(
uint uTimerID, uint uTimerId,
uint uMsg, uint uMsg,
int dwUser, int dwUser,
int dw1, int dw1,

View File

@@ -22,7 +22,7 @@ public sealed class MusicPlayer : IMusicPlayer
public float Volume { get; private set; } = 1.0f; public float Volume { get; private set; } = 1.0f;
private readonly AdjustVolumeDelegate AdjustVolume; private readonly AdjustVolumeDelegate _adjustVolume;
private readonly VoiceClient _vc; private readonly VoiceClient _vc;
private readonly IMusicQueue _queue; private readonly IMusicQueue _queue;
@@ -30,8 +30,8 @@ public sealed class MusicPlayer : IMusicPlayer
private readonly IVoiceProxy _proxy; private readonly IVoiceProxy _proxy;
private readonly ISongBuffer _songBuffer; private readonly ISongBuffer _songBuffer;
private bool _skipped; private bool skipped;
private int? _forceIndex; private int? forceIndex;
private readonly Thread _thread; private readonly Thread _thread;
private readonly Random _rng; private readonly Random _rng;
@@ -48,9 +48,9 @@ public sealed class MusicPlayer : IMusicPlayer
_vc = GetVoiceClient(qualityPreset); _vc = GetVoiceClient(qualityPreset);
if (_vc.BitDepth == 16) if (_vc.BitDepth == 16)
AdjustVolume = AdjustVolumeInt16; _adjustVolume = AdjustVolumeInt16;
else else
AdjustVolume = AdjustVolumeFloat32; _adjustVolume = AdjustVolumeFloat32;
_songBuffer = new PoopyBufferImmortalized(_vc.InputLength); _songBuffer = new PoopyBufferImmortalized(_vc.InputLength);
@@ -95,9 +95,9 @@ public sealed class MusicPlayer : IMusicPlayer
continue; continue;
} }
if (_skipped) if (skipped)
{ {
_skipped = false; skipped = false;
_queue.Advance(); _queue.Advance();
continue; continue;
} }
@@ -182,9 +182,9 @@ public sealed class MusicPlayer : IMusicPlayer
{ {
// doing the skip this way instead of in the condition // doing the skip this way instead of in the condition
// ensures that a song will for sure be skipped // ensures that a song will for sure be skipped
if (_skipped) if (skipped)
{ {
_skipped = false; skipped = false;
break; break;
} }
@@ -268,10 +268,9 @@ public sealed class MusicPlayer : IMusicPlayer
_ = OnCompleted?.Invoke(this, track); _ = OnCompleted?.Invoke(this, track);
HandleQueuePostTrack(); HandleQueuePostTrack();
_skipped = false; skipped = false;
_ = _proxy.StopSpeakingAsync(); _ = _proxy.StopSpeakingAsync();
;
await Task.Delay(100); await Task.Delay(100);
} }
@@ -285,16 +284,16 @@ public sealed class MusicPlayer : IMusicPlayer
// if nothing is read from the buffer, song is finished // if nothing is read from the buffer, song is finished
if (data.Length == 0) return null; if (data.Length == 0) return null;
AdjustVolume(data, Volume); _adjustVolume(data, Volume);
return _proxy.SendPcmFrame(vc, data, length); return _proxy.SendPcmFrame(vc, data, length);
} }
private void HandleQueuePostTrack() private void HandleQueuePostTrack()
{ {
if (_forceIndex is { } forceIndex) if (this.forceIndex is { } forceIndex)
{ {
_queue.SetIndex(forceIndex); _queue.SetIndex(forceIndex);
_forceIndex = null; this.forceIndex = null;
return; return;
} }
@@ -419,7 +418,7 @@ public sealed class MusicPlayer : IMusicPlayer
public void Clear() public void Clear()
{ {
_queue.Clear(); _queue.Clear();
_skipped = true; skipped = true;
} }
public IReadOnlyCollection<IQueuedTrackInfo> GetQueuedTracks() public IReadOnlyCollection<IQueuedTrackInfo> GetQueuedTracks()
@@ -430,7 +429,7 @@ public sealed class MusicPlayer : IMusicPlayer
public void Next() public void Next()
{ {
_skipped = true; skipped = true;
IsStopped = false; IsStopped = false;
IsPaused = false; IsPaused = false;
} }
@@ -439,8 +438,8 @@ public sealed class MusicPlayer : IMusicPlayer
{ {
if (_queue.SetIndex(index)) if (_queue.SetIndex(index))
{ {
_forceIndex = index; forceIndex = index;
_skipped = true; skipped = true;
IsStopped = false; IsStopped = false;
IsPaused = false; IsPaused = false;
return true; return true;
@@ -463,7 +462,7 @@ public sealed class MusicPlayer : IMusicPlayer
IsKilled = true; IsKilled = true;
IsStopped = true; IsStopped = true;
IsPaused = false; IsPaused = false;
_skipped = true; skipped = true;
} }
public bool TryRemoveTrackAt(int index, out IQueuedTrackInfo? trackInfo) public bool TryRemoveTrackAt(int index, out IQueuedTrackInfo? trackInfo)
@@ -472,7 +471,7 @@ public sealed class MusicPlayer : IMusicPlayer
return false; return false;
if (isCurrent) if (isCurrent)
_skipped = true; skipped = true;
return true; return true;
} }

View File

@@ -91,7 +91,7 @@ public sealed partial class MusicQueue : IMusicQueue
var currentNode = tracks.First!; var currentNode = tracks.First!;
int i; int i;
for (i = 1; i <= this.index; i++) for (i = 1; i <= index; i++)
currentNode = currentNode.Next!; // can't be null because index is always in range of the count currentNode = currentNode.Next!; // can't be null because index is always in range of the count
var added = new QueuedTrackInfo(trackInfo, queuer); var added = new QueuedTrackInfo(trackInfo, queuer);
@@ -110,7 +110,7 @@ public sealed partial class MusicQueue : IMusicQueue
foreach (var track in toEnqueue) foreach (var track in toEnqueue)
{ {
var added = new QueuedTrackInfo(track, queuer); var added = new QueuedTrackInfo(track, queuer);
this.tracks.AddLast(added); tracks.AddLast(added);
} }
} }
} }
@@ -156,7 +156,7 @@ public sealed partial class MusicQueue : IMusicQueue
if (newIndex < 0 || newIndex >= tracks.Count) if (newIndex < 0 || newIndex >= tracks.Count)
return false; return false;
this.index = newIndex; index = newIndex;
return true; return true;
} }
} }
@@ -170,11 +170,11 @@ public sealed partial class MusicQueue : IMusicQueue
trackInfo = removedNode.Value; trackInfo = removedNode.Value;
tracks.Remove(removedNode); tracks.Remove(removedNode);
if (i <= this.index) if (i <= index)
--this.index; --index;
if (this.index < 0) if (index < 0)
this.index = Count; index = Count;
// if it was the last song in the queue // if it was the last song in the queue
// // wrap back to start // // wrap back to start
@@ -303,7 +303,7 @@ public sealed partial class MusicQueue : IMusicQueue
if (remoteAt < 0 || remoteAt >= tracks.Count) if (remoteAt < 0 || remoteAt >= tracks.Count)
return false; return false;
if (remoteAt == this.index) isCurrent = true; if (remoteAt == index) isCurrent = true;
RemoveAtInternal(remoteAt, out trackInfo); RemoveAtInternal(remoteAt, out trackInfo);

View File

@@ -5,12 +5,12 @@ namespace NadekoBot.Modules.Music;
public sealed class YtdlYoutubeResolver : IYoutubeResolver public sealed class YtdlYoutubeResolver : IYoutubeResolver
{ {
private static readonly string[] durationFormats = private static readonly string[] _durationFormats =
{ {
"ss", "m\\:ss", "mm\\:ss", "h\\:mm\\:ss", "hh\\:mm\\:ss", "hhh\\:mm\\:ss" "ss", "m\\:ss", "mm\\:ss", "h\\:mm\\:ss", "hh\\:mm\\:ss", "hhh\\:mm\\:ss"
}; };
private static readonly Regex expiryRegex = new(@"(?:[\?\&]expire\=(?<timestamp>\d+))"); private static readonly Regex _expiryRegex = new(@"(?:[\?\&]expire\=(?<timestamp>\d+))");
private static readonly Regex _simplePlaylistRegex = new(@"&list=(?<id>[\w\-]{12,})", RegexOptions.Compiled); private static readonly Regex _simplePlaylistRegex = new(@"&list=(?<id>[\w\-]{12,})", RegexOptions.Compiled);
@@ -85,7 +85,7 @@ public sealed class YtdlYoutubeResolver : IYoutubeResolver
return default; return default;
} }
if (!TimeSpan.TryParseExact(dataArray[4], durationFormats, CultureInfo.InvariantCulture, out var time)) if (!TimeSpan.TryParseExact(dataArray[4], _durationFormats, CultureInfo.InvariantCulture, out var time))
time = TimeSpan.Zero; time = TimeSpan.Zero;
var thumbnail = Uri.IsWellFormedUriString(dataArray[3], UriKind.Absolute) ? dataArray[3].Trim() : string.Empty; var thumbnail = Uri.IsWellFormedUriString(dataArray[3], UriKind.Absolute) ? dataArray[3].Trim() : string.Empty;
@@ -108,7 +108,7 @@ public sealed class YtdlYoutubeResolver : IYoutubeResolver
private static TimeSpan GetExpiry(string streamUrl) private static TimeSpan GetExpiry(string streamUrl)
{ {
var match = expiryRegex.Match(streamUrl); var match = _expiryRegex.Match(streamUrl);
if (match.Success && double.TryParse(match.Groups["timestamp"].ToString(), out var timestamp)) if (match.Success && double.TryParse(match.Groups["timestamp"].ToString(), out var timestamp))
{ {
var realExpiry = timestamp.ToUnixTimestamp() - DateTime.UtcNow; var realExpiry = timestamp.ToUnixTimestamp() - DateTime.UtcNow;

View File

@@ -36,7 +36,7 @@ public partial class NSFW : NadekoModule<ISearchImagesService>
} }
} }
private async Task InternalButts(IMessageChannel Channel) private async Task InternalButts(IMessageChannel channel)
{ {
try try
{ {
@@ -47,7 +47,7 @@ public partial class NSFW : NadekoModule<ISearchImagesService>
await http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}"))[0]; await http.GetStringAsync($"http://api.obutts.ru/butts/{new NadekoRandom().Next(0, 4335)}"))[0];
} }
await Channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}"); await channel.SendMessageAsync($"http://media.obutts.ru/{obj["preview"]}");
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -35,7 +35,7 @@ public class SearchImagesService : ISearchImagesService, INService
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly DbService _db; private readonly DbService _db;
private readonly object taglock = new(); private readonly object _taglock = new();
public SearchImagesService( public SearchImagesService(
DbService db, DbService db,
@@ -188,7 +188,7 @@ public class SearchImagesService : ISearchImagesService, INService
public ValueTask<bool> ToggleBlacklistTag(ulong guildId, string tag) public ValueTask<bool> ToggleBlacklistTag(ulong guildId, string tag)
{ {
lock (taglock) lock (_taglock)
{ {
tag = tag.Trim().ToLowerInvariant(); tag = tag.Trim().ToLowerInvariant();
var blacklistedTags = BlacklistedTags.GetOrAdd(guildId, new HashSet<string>()); var blacklistedTags = BlacklistedTags.GetOrAdd(guildId, new HashSet<string>());
@@ -214,7 +214,7 @@ public class SearchImagesService : ISearchImagesService, INService
public ValueTask<string[]> GetBlacklistedTags(ulong guildId) public ValueTask<string[]> GetBlacklistedTags(ulong guildId)
{ {
lock (taglock) lock (_taglock)
{ {
if (BlacklistedTags.TryGetValue(guildId, out var tags)) return new(tags.ToArray()); if (BlacklistedTags.TryGetValue(guildId, out var tags)) return new(tags.ToArray());

View File

@@ -10,7 +10,7 @@ public abstract class ImageDownloader<T> : IImageDownloader
public Booru Booru { get; } public Booru Booru { get; }
protected readonly HttpClient _http; protected readonly HttpClient _http;
protected JsonSerializerOptions _serializerOptions = new() protected readonly JsonSerializerOptions _serializerOptions = new()
{ {
PropertyNameCaseInsensitive = true, PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString NumberHandling = JsonNumberHandling.WriteAsString | JsonNumberHandling.AllowReadingFromString

View File

@@ -30,7 +30,7 @@ public sealed class BlacklistService : IEarlyBehavior
private ValueTask OnReload(BlacklistEntry[] newBlacklist) private ValueTask OnReload(BlacklistEntry[] newBlacklist)
{ {
this.blacklist = newBlacklist; blacklist = newBlacklist;
return default; return default;
} }

View File

@@ -9,7 +9,7 @@ public partial class Permissions
[Group] [Group]
public partial class GlobalPermissionCommands : NadekoSubmodule public partial class GlobalPermissionCommands : NadekoSubmodule
{ {
private GlobalPermissionService _service; private readonly GlobalPermissionService _service;
private readonly DbService _db; private readonly DbService _db;
public GlobalPermissionCommands(GlobalPermissionService service, DbService db) public GlobalPermissionCommands(GlobalPermissionService service, DbService db)

View File

@@ -10,7 +10,7 @@ public class CryptoService : INService
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly SemaphoreSlim getCryptoLock = new(1, 1); private readonly SemaphoreSlim _getCryptoLock = new(1, 1);
public CryptoService(IDataCache cache, IHttpClientFactory httpFactory, IBotCredentials creds) public CryptoService(IDataCache cache, IHttpClientFactory httpFactory, IBotCredentials creds)
{ {
@@ -52,7 +52,7 @@ public class CryptoService : INService
public async Task<List<CryptoResponseData>> CryptoData() public async Task<List<CryptoResponseData>> CryptoData()
{ {
await getCryptoLock.WaitAsync(); await _getCryptoLock.WaitAsync();
try try
{ {
var fullStrData = await _cache.GetOrAddCachedDataAsync("nadeko:crypto_data", var fullStrData = await _cache.GetOrAddCachedDataAsync("nadeko:crypto_data",
@@ -81,7 +81,7 @@ public class CryptoService : INService
"", "",
TimeSpan.FromHours(1)); TimeSpan.FromHours(1));
return JsonConvert.DeserializeObject<CryptoResponse>(fullStrData).Data; return JsonConvert.DeserializeObject<CryptoResponse>(fullStrData)?.Data ?? new();
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -90,7 +90,7 @@ public class CryptoService : INService
} }
finally finally
{ {
getCryptoLock.Release(); _getCryptoLock.Release();
} }
} }
} }

View File

@@ -10,7 +10,7 @@ public partial class Searches
[Group] [Group]
public partial class FeedCommands : NadekoSubmodule<FeedsService> public partial class FeedCommands : NadekoSubmodule<FeedsService>
{ {
private static readonly Regex YtChannelRegex = private static readonly Regex _ytChannelRegex =
new(@"youtube\.com\/(?:c\/|channel\/|user\/)?(?<channelid>[a-zA-Z0-9\-]{1,})"); new(@"youtube\.com\/(?:c\/|channel\/|user\/)?(?<channelid>[a-zA-Z0-9\-]{1,})");
[Cmd] [Cmd]
@@ -18,7 +18,7 @@ public partial class Searches
[UserPerm(GuildPerm.ManageMessages)] [UserPerm(GuildPerm.ManageMessages)]
public partial Task YtUploadNotif(string url, [Leftover] ITextChannel channel = null) public partial Task YtUploadNotif(string url, [Leftover] ITextChannel channel = null)
{ {
var m = YtChannelRegex.Match(url); var m = _ytChannelRegex.Match(url);
if (!m.Success) return ReplyErrorLocalizedAsync(strs.invalid_input); if (!m.Success) return ReplyErrorLocalizedAsync(strs.invalid_input);
var channelId = m.Groups["channelid"].Value; var channelId = m.Groups["channelid"].Value;
@@ -38,7 +38,7 @@ public partial class Searches
channel ??= (ITextChannel)ctx.Channel; channel ??= (ITextChannel)ctx.Channel;
try try
{ {
var feeds = await FeedReader.ReadAsync(url); await FeedReader.ReadAsync(url);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@@ -115,7 +115,6 @@ public partial class Searches
[Cmd] [Cmd]
public async partial Task Osu5(string user, [Leftover] string mode = null) public async partial Task Osu5(string user, [Leftover] string mode = null)
{ {
;
if (string.IsNullOrWhiteSpace(_creds.OsuApiKey)) if (string.IsNullOrWhiteSpace(_creds.OsuApiKey))
{ {
await SendErrorAsync("An osu! API key is required."); await SendErrorAsync("An osu! API key is required.");

View File

@@ -46,7 +46,7 @@ public class SearchesService : INService
private readonly NadekoRandom _rng; private readonly NadekoRandom _rng;
private readonly List<string> _yomamaJokes; private readonly List<string> _yomamaJokes;
private readonly object yomamaLock = new(); private readonly object _yomamaLock = new();
private int yomamaJokeIndex; private int yomamaJokeIndex;
public SearchesService( public SearchesService(
@@ -224,9 +224,11 @@ public class SearchesService : INService
using var req = new HttpRequestMessage(HttpMethod.Get, using var req = new HttpRequestMessage(HttpMethod.Get,
"http://api.timezonedb.com/v2.1/get-time-zone?" "http://api.timezonedb.com/v2.1/get-time-zone?"
+ $"key={_creds.TimezoneDbApiKey}&format=json&" + $"key={_creds.TimezoneDbApiKey}"
+ "by=position&" + $"&format=json"
+ $"lat={geoData.Lat}&lng={geoData.Lon}"); + $"&by=position"
+ $"&lat={geoData.Lat}"
+ $"&lng={geoData.Lon}");
using var geoRes = await http.SendAsync(req); using var geoRes = await http.SendAsync(req);
var resString = await geoRes.Content.ReadAsStringAsync(); var resString = await geoRes.Content.ReadAsStringAsync();
var timeObj = JsonConvert.DeserializeObject<TimeZoneResult>(resString); var timeObj = JsonConvert.DeserializeObject<TimeZoneResult>(resString);
@@ -274,7 +276,7 @@ public class SearchesService : INService
public Task<string> GetYomamaJoke() public Task<string> GetYomamaJoke()
{ {
string joke; string joke;
lock (yomamaLock) lock (_yomamaLock)
{ {
if (yomamaJokeIndex >= _yomamaJokes.Count) if (yomamaJokeIndex >= _yomamaJokes.Count)
{ {
@@ -428,8 +430,6 @@ public class SearchesService : INService
public async Task<int> GetSteamAppIdByName(string query) public async Task<int> GetSteamAppIdByName(string query)
{ {
var redis = _cache.Redis;
var db = redis.GetDatabase();
const string steamGameIdsKey = "steam_names_to_appid"; const string steamGameIdsKey = "steam_names_to_appid";
// var exists = await db.KeyExistsAsync(steamGameIdsKey); // var exists = await db.KeyExistsAsync(steamGameIdsKey);

View File

@@ -59,7 +59,7 @@ public partial class Searches
[UserPerm(GuildPerm.Administrator)] [UserPerm(GuildPerm.Administrator)]
public async partial Task StreamsClear() public async partial Task StreamsClear()
{ {
var count = _service.ClearAllStreams(ctx.Guild.Id); await _service.ClearAllStreams(ctx.Guild.Id);
await ReplyConfirmLocalizedAsync(strs.streams_cleared); await ReplyConfirmLocalizedAsync(strs.streams_cleared);
} }

View File

@@ -116,7 +116,7 @@ public sealed class StreamNotificationService : INService
return; return;
var deleteGroups = failingStreams.GroupBy(x => x.Type) var deleteGroups = failingStreams.GroupBy(x => x.Type)
.ToDictionary(x => x.Key, x => x.Select(x => x.Name).ToList()); .ToDictionary(x => x.Key, x => x.Select(y => y.Name).ToList());
using var uow = _db.GetDbContext(); using var uow = _db.GetDbContext();
foreach (var kvp in deleteGroups) foreach (var kvp in deleteGroups)

View File

@@ -1,5 +1,4 @@
#nullable disable #nullable disable
namespace NadekoBot.Modules.Searches.Services;
// public class YtTrackService : INService // public class YtTrackService : INService
// { // {

View File

@@ -1,22 +0,0 @@
#nullable disable
namespace NadekoBot.Modules.Searches.Common;
//
// public class TwitchResponse
// {
// public List<StreamApiData> Data { get; set; }
//
// public class StreamApiData
// {
// public string Id { get; set; }
// public string UserId { get; set; }
// public string UserName { get; set; }
// public string GameId { get; set; }
// public string Type { get; set; }
// public string Title { get; set; }
// public int ViewerCount { get; set; }
// public string Language { get; set; }
// public string ThumbnailUrl { get; set; }
// public DateTime StartedAt { get; set; }
// }
// }

View File

@@ -34,8 +34,6 @@ public partial class Utility
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async partial Task Alias(string trigger, [Leftover] string mapping = null) public async partial Task Alias(string trigger, [Leftover] string mapping = null)
{ {
var channel = (ITextChannel)ctx.Channel;
if (string.IsNullOrWhiteSpace(trigger)) if (string.IsNullOrWhiteSpace(trigger))
return; return;
@@ -52,7 +50,6 @@ public partial class Utility
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
var config = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(x => x.CommandAliases)); var config = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(x => x.CommandAliases));
var toAdd = new CommandAlias { Mapping = mapping, Trigger = trigger };
var tr = config.CommandAliases.FirstOrDefault(x => x.Trigger == trigger); var tr = config.CommandAliases.FirstOrDefault(x => x.Trigger == trigger);
if (tr is not null) if (tr is not null)
uow.Set<CommandAlias>().Remove(tr); uow.Set<CommandAlias>().Remove(tr);
@@ -84,9 +81,9 @@ public partial class Utility
{ {
var config = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(x => x.CommandAliases)); var config = uow.GuildConfigsForId(ctx.Guild.Id, set => set.Include(x => x.CommandAliases));
var toAdd = new CommandAlias { Mapping = mapping, Trigger = trigger }; var toAdd = new CommandAlias { Mapping = mapping, Trigger = trigger };
var toRemove = config.CommandAliases.Where(x => x.Trigger == trigger); var toRemove = config.CommandAliases.Where(x => x.Trigger == trigger).ToArray();
if (toRemove.Any()) if (toRemove.Any())
uow.RemoveRange(toRemove.ToArray()); uow.RemoveRange(toRemove);
config.CommandAliases.Add(toAdd); config.CommandAliases.Add(toAdd);
uow.SaveChanges(); uow.SaveChanges();
} }
@@ -103,7 +100,6 @@ public partial class Utility
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async partial Task AliasList(int page = 1) public async partial Task AliasList(int page = 1)
{ {
var channel = (ITextChannel)ctx.Channel;
page -= 1; page -= 1;
if (page < 0) if (page < 0)

View File

@@ -107,7 +107,7 @@ public partial class Utility
if (string.IsNullOrWhiteSpace(value)) if (string.IsNullOrWhiteSpace(value))
value = "-"; value = "-";
if (prop != "currency.sign") value = Format.Code(Format.Sanitize(value?.TrimTo(1000)), "json"); if (prop != "currency.sign") value = Format.Code(Format.Sanitize(value.TrimTo(1000)), "json");
var embed = _eb.Create() var embed = _eb.Create()
.WithOkColor() .WithOkColor()
@@ -134,7 +134,7 @@ public partial class Utility
await ctx.OkAsync(); await ctx.OkAsync();
} }
private string GetPropsAndValuesString(IConfigService config, IEnumerable<string> names) private string GetPropsAndValuesString(IConfigService config, IReadOnlyCollection<string> names)
{ {
var propValues = names.Select(pr => var propValues = names.Select(pr =>
{ {
@@ -142,7 +142,7 @@ public partial class Utility
if (pr != "currency.sign") if (pr != "currency.sign")
val = val?.TrimTo(28); val = val?.TrimTo(28);
return val?.Replace("\n", "") ?? "-"; return val?.Replace("\n", "") ?? "-";
}); }).ToList();
var strings = names.Zip(propValues, (name, value) => $"{name,-25} = {value}\n"); var strings = names.Zip(propValues, (name, value) => $"{name,-25} = {value}\n");

View File

@@ -150,7 +150,7 @@ public class PatreonRewardsService : INService
+ "?fields%5Bmember%5D=full_name,currently_entitled_amount_cents" + "?fields%5Bmember%5D=full_name,currently_entitled_amount_cents"
+ "&fields%5Buser%5D=social_connections" + "&fields%5Buser%5D=social_connections"
+ "&include=user"; + "&include=user";
PatreonResponse data = null; PatreonResponse data;
do do
{ {
var res = await http.GetStringAsync(page); var res = await http.GetStringAsync(page);

View File

@@ -62,12 +62,16 @@ public partial class Utility
} }
if (quotes.Any()) if (quotes.Any())
{
await SendConfirmAsync(GetText(strs.quotes_page(page + 1)), await SendConfirmAsync(GetText(strs.quotes_page(page + 1)),
string.Join("\n", string.Join("\n",
quotes.Select(q quotes.Select(q
=> $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}"))); => $"`#{q.Id}` {Format.Bold(q.Keyword.SanitizeAllMentions()),-20} by {q.AuthorName.SanitizeAllMentions()}")));
}
else else
{
await ReplyErrorLocalizedAsync(strs.quotes_page_none); await ReplyErrorLocalizedAsync(strs.quotes_page_none);
}
} }
[Cmd] [Cmd]

View File

@@ -55,7 +55,6 @@ public sealed class RunningRepeater
/// <summary> /// <summary>
/// Calculate when is the proper time to run the repeater again based on initial time repeater ran. /// Calculate when is the proper time to run the repeater again based on initial time repeater ran.
/// </summary> /// </summary>
/// <param name="repeaterter"></param>
/// <param name="initialDateTime">Initial time repeater ran at (or should run at).</param> /// <param name="initialDateTime">Initial time repeater ran at (or should run at).</param>
private DateTime CalculateInitialInterval(DateTime initialDateTime) private DateTime CalculateInitialInterval(DateTime initialDateTime)
{ {

View File

@@ -23,7 +23,7 @@ public class ConverterService : INService
_httpFactory = factory; _httpFactory = factory;
if (client.ShardId == 0) if (client.ShardId == 0)
_currencyUpdater = new(async shouldLoad => await UpdateCurrency((bool)shouldLoad), _currencyUpdater = new(async shouldLoad => await UpdateCurrency((bool)shouldLoad!),
client.ShardId == 0, client.ShardId == 0,
TimeSpan.Zero, TimeSpan.Zero,
_updateInterval); _updateInterval);
@@ -55,7 +55,9 @@ public class ConverterService : INService
.ToArray(); .ToArray();
var fileData = JsonConvert.DeserializeObject<ConvertUnit[]>(File.ReadAllText("data/units.json")) var fileData = JsonConvert.DeserializeObject<ConvertUnit[]>(File.ReadAllText("data/units.json"))
.Where(x => x.UnitType != "currency"); ?.Where(x => x.UnitType != "currency");
if (fileData is null)
return;
var data = JsonConvert.SerializeObject(range.Append(baseType).Concat(fileData).ToList()); var data = JsonConvert.SerializeObject(range.Append(baseType).Concat(fileData).ToList());
_cache.Redis.GetDatabase().StringSet("converter_units", data); _cache.Redis.GetDatabase().StringSet("converter_units", data);

View File

@@ -6,7 +6,7 @@ namespace NadekoBot.Modules.Utility.Services;
public class VerboseErrorsService : INService public class VerboseErrorsService : INService
{ {
private readonly ConcurrentHashSet<ulong> guildsEnabled; private readonly ConcurrentHashSet<ulong> _guildsEnabled;
private readonly DbService _db; private readonly DbService _db;
private readonly CommandHandler _ch; private readonly CommandHandler _ch;
private readonly HelpService _hs; private readonly HelpService _hs;
@@ -23,12 +23,12 @@ public class VerboseErrorsService : INService
_ch.CommandErrored += LogVerboseError; _ch.CommandErrored += LogVerboseError;
guildsEnabled = new(bot.AllGuildConfigs.Where(x => x.VerboseErrors).Select(x => x.GuildId)); _guildsEnabled = new(bot.AllGuildConfigs.Where(x => x.VerboseErrors).Select(x => x.GuildId));
} }
private async Task LogVerboseError(CommandInfo cmd, ITextChannel channel, string reason) private async Task LogVerboseError(CommandInfo cmd, ITextChannel channel, string reason)
{ {
if (channel is null || !guildsEnabled.Contains(channel.GuildId)) if (channel is null || !_guildsEnabled.Contains(channel.GuildId))
return; return;
try try
@@ -60,9 +60,9 @@ public class VerboseErrorsService : INService
} }
if ((bool)enabled) // This doesn't need to be duplicated inside the using block if ((bool)enabled) // This doesn't need to be duplicated inside the using block
guildsEnabled.Add(guildId); _guildsEnabled.Add(guildId);
else else
guildsEnabled.TryRemove(guildId); _guildsEnabled.TryRemove(guildId);
return (bool)enabled; return (bool)enabled;
} }

View File

@@ -9,10 +9,10 @@ public class ClubService : INService
private readonly DbService _db; private readonly DbService _db;
private readonly IHttpClientFactory _httpFactory; private readonly IHttpClientFactory _httpFactory;
public ClubService(DbService db, IHttpClientFactory _httpFactory) public ClubService(DbService db, IHttpClientFactory httpFactory)
{ {
_db = db; _db = db;
this._httpFactory = _httpFactory; _httpFactory = httpFactory;
} }
public bool CreateClub(IUser user, string clubName, out ClubInfo club) public bool CreateClub(IUser user, string clubName, out ClubInfo club)

View File

@@ -5,12 +5,13 @@ namespace NadekoBot.Modules.Xp.Services;
public sealed class XpConfigService : ConfigServiceBase<XpConfig> public sealed class XpConfigService : ConfigServiceBase<XpConfig>
{ {
private const string FilePath = "data/xp.yml"; private const string FILE_PATH = "data/xp.yml";
private static readonly TypedKey<XpConfig> changeKey = new("config.xp.updated"); private static readonly TypedKey<XpConfig> _changeKey = new("config.xp.updated");
public override string Name { get; } = "xp"; public override string Name
=> "xp";
public XpConfigService(IConfigSeria serializer, IPubSub pubSub) public XpConfigService(IConfigSeria serializer, IPubSub pubSub)
: base(FilePath, serializer, pubSub, changeKey) : base(FILE_PATH, serializer, pubSub, _changeKey)
{ {
AddParsedProp("txt.cooldown", AddParsedProp("txt.cooldown",
conf => conf.MessageXpCooldown, conf => conf.MessageXpCooldown,

View File

@@ -42,7 +42,7 @@ public class XpService : INService
private readonly ConcurrentHashSet<ulong> _excludedServers; private readonly ConcurrentHashSet<ulong> _excludedServers;
private readonly ConcurrentQueue<UserCacheItem> _addMessageXp = new(); private readonly ConcurrentQueue<UserCacheItem> _addMessageXp = new();
private XpTemplate _template; private XpTemplate template;
private readonly DiscordSocketClient _client; private readonly DiscordSocketClient _client;
private readonly TypedKey<bool> _xpTemplateReloadKey; private readonly TypedKey<bool> _xpTemplateReloadKey;
@@ -266,15 +266,15 @@ public class XpService : INService
{ {
ContractResolver = new RequireObjectPropertiesContractResolver() ContractResolver = new RequireObjectPropertiesContractResolver()
}; };
_template = JsonConvert.DeserializeObject<XpTemplate>(File.ReadAllText("./data/xp_template.json"), template = JsonConvert.DeserializeObject<XpTemplate>(File.ReadAllText("./data/xp_template.json"),
settings); settings);
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error(ex, "Xp template is invalid. Loaded default values"); Log.Error(ex, "Xp template is invalid. Loaded default values");
_template = new(); template = new();
File.WriteAllText("./data/xp_template_backup.json", File.WriteAllText("./data/xp_template_backup.json",
JsonConvert.SerializeObject(_template, Formatting.Indented)); JsonConvert.SerializeObject(template, Formatting.Indented));
} }
} }
@@ -583,7 +583,7 @@ public class XpService : INService
public async Task<FullUserStats> GetUserStatsAsync(IGuildUser user) public async Task<FullUserStats> GetUserStatsAsync(IGuildUser user)
{ {
DiscordUser du; DiscordUser du;
UserXpStats stats = null; UserXpStats stats;
int totalXp; int totalXp;
int globalRank; int globalRank;
int guildRank; int guildRank;
@@ -691,58 +691,58 @@ public class XpService : INService
}.WithFallbackFonts(_fonts.FallBackFonts); }.WithFallbackFonts(_fonts.FallBackFonts);
using var img = Image.Load<Rgba32>(_images.XpBackground, out var imageFormat); using var img = Image.Load<Rgba32>(_images.XpBackground, out var imageFormat);
if (_template.User.Name.Show) if (template.User.Name.Show)
{ {
var fontSize = (int)(_template.User.Name.FontSize * 0.9); var fontSize = (int)(template.User.Name.FontSize * 0.9);
var username = stats.User.ToString(); var username = stats.User.ToString();
var usernameFont = _fonts.NotoSans.CreateFont(fontSize, FontStyle.Bold); var usernameFont = _fonts.NotoSans.CreateFont(fontSize, FontStyle.Bold);
var size = TextMeasurer.Measure($"@{username}", new(usernameFont)); var size = TextMeasurer.Measure($"@{username}", new(usernameFont));
var scale = 400f / size.Width; var scale = 400f / size.Width;
if (scale < 1) if (scale < 1)
usernameFont = _fonts.NotoSans.CreateFont(_template.User.Name.FontSize * scale, FontStyle.Bold); usernameFont = _fonts.NotoSans.CreateFont(template.User.Name.FontSize * scale, FontStyle.Bold);
img.Mutate(x => img.Mutate(x =>
{ {
x.DrawText(usernameTextOptions, x.DrawText(usernameTextOptions,
"@" + username, "@" + username,
usernameFont, usernameFont,
_template.User.Name.Color, template.User.Name.Color,
new(_template.User.Name.Pos.X, _template.User.Name.Pos.Y + 8)); new(template.User.Name.Pos.X, template.User.Name.Pos.Y + 8));
}); });
} }
//club name //club name
if (_template.Club.Name.Show) if (template.Club.Name.Show)
{ {
var clubName = stats.User.Club?.ToString() ?? "-"; var clubName = stats.User.Club?.ToString() ?? "-";
var clubFont = _fonts.NotoSans.CreateFont(_template.Club.Name.FontSize, FontStyle.Regular); var clubFont = _fonts.NotoSans.CreateFont(template.Club.Name.FontSize, FontStyle.Regular);
img.Mutate(x => x.DrawText(clubTextOptions, img.Mutate(x => x.DrawText(clubTextOptions,
clubName, clubName,
clubFont, clubFont,
_template.Club.Name.Color, template.Club.Name.Color,
new(_template.Club.Name.Pos.X + 50, _template.Club.Name.Pos.Y - 8))); new(template.Club.Name.Pos.X + 50, template.Club.Name.Pos.Y - 8)));
} }
if (_template.User.GlobalLevel.Show) if (template.User.GlobalLevel.Show)
img.Mutate(x => img.Mutate(x =>
{ {
x.DrawText(stats.Global.Level.ToString(), x.DrawText(stats.Global.Level.ToString(),
_fonts.NotoSans.CreateFont(_template.User.GlobalLevel.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.GlobalLevel.FontSize, FontStyle.Bold),
_template.User.GlobalLevel.Color, template.User.GlobalLevel.Color,
new(_template.User.GlobalLevel.Pos.X, _template.User.GlobalLevel.Pos.Y)); //level new(template.User.GlobalLevel.Pos.X, template.User.GlobalLevel.Pos.Y)); //level
}); });
if (_template.User.GuildLevel.Show) if (template.User.GuildLevel.Show)
img.Mutate(x => img.Mutate(x =>
{ {
x.DrawText(stats.Guild.Level.ToString(), x.DrawText(stats.Guild.Level.ToString(),
_fonts.NotoSans.CreateFont(_template.User.GuildLevel.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.GuildLevel.FontSize, FontStyle.Bold),
_template.User.GuildLevel.Color, template.User.GuildLevel.Color,
new(_template.User.GuildLevel.Pos.X, _template.User.GuildLevel.Pos.Y)); new(template.User.GuildLevel.Pos.X, template.User.GuildLevel.Pos.Y));
}); });
@@ -752,53 +752,53 @@ public class XpService : INService
var guild = stats.Guild; var guild = stats.Guild;
//xp bar //xp bar
if (_template.User.Xp.Bar.Show) if (template.User.Xp.Bar.Show)
{ {
var xpPercent = global.LevelXp / (float)global.RequiredXp; var xpPercent = global.LevelXp / (float)global.RequiredXp;
DrawXpBar(xpPercent, _template.User.Xp.Bar.Global, img); DrawXpBar(xpPercent, template.User.Xp.Bar.Global, img);
xpPercent = guild.LevelXp / (float)guild.RequiredXp; xpPercent = guild.LevelXp / (float)guild.RequiredXp;
DrawXpBar(xpPercent, _template.User.Xp.Bar.Guild, img); DrawXpBar(xpPercent, template.User.Xp.Bar.Guild, img);
} }
if (_template.User.Xp.Global.Show) if (template.User.Xp.Global.Show)
img.Mutate(x => x.DrawText($"{global.LevelXp}/{global.RequiredXp}", img.Mutate(x => x.DrawText($"{global.LevelXp}/{global.RequiredXp}",
_fonts.NotoSans.CreateFont(_template.User.Xp.Global.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.Xp.Global.FontSize, FontStyle.Bold),
Brushes.Solid(_template.User.Xp.Global.Color), Brushes.Solid(template.User.Xp.Global.Color),
pen, pen,
new(_template.User.Xp.Global.Pos.X, _template.User.Xp.Global.Pos.Y))); new(template.User.Xp.Global.Pos.X, template.User.Xp.Global.Pos.Y)));
if (_template.User.Xp.Guild.Show) if (template.User.Xp.Guild.Show)
img.Mutate(x => x.DrawText($"{guild.LevelXp}/{guild.RequiredXp}", img.Mutate(x => x.DrawText($"{guild.LevelXp}/{guild.RequiredXp}",
_fonts.NotoSans.CreateFont(_template.User.Xp.Guild.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.Xp.Guild.FontSize, FontStyle.Bold),
Brushes.Solid(_template.User.Xp.Guild.Color), Brushes.Solid(template.User.Xp.Guild.Color),
pen, pen,
new(_template.User.Xp.Guild.Pos.X, _template.User.Xp.Guild.Pos.Y))); new(template.User.Xp.Guild.Pos.X, template.User.Xp.Guild.Pos.Y)));
if (stats.FullGuildStats.AwardedXp != 0 && _template.User.Xp.Awarded.Show) if (stats.FullGuildStats.AwardedXp != 0 && template.User.Xp.Awarded.Show)
{ {
var sign = stats.FullGuildStats.AwardedXp > 0 ? "+ " : ""; var sign = stats.FullGuildStats.AwardedXp > 0 ? "+ " : "";
var awX = _template.User.Xp.Awarded.Pos.X var awX = template.User.Xp.Awarded.Pos.X
- (Math.Max(0, stats.FullGuildStats.AwardedXp.ToString().Length - 2) * 5); - (Math.Max(0, stats.FullGuildStats.AwardedXp.ToString().Length - 2) * 5);
var awY = _template.User.Xp.Awarded.Pos.Y; var awY = template.User.Xp.Awarded.Pos.Y;
img.Mutate(x => x.DrawText($"({sign}{stats.FullGuildStats.AwardedXp})", img.Mutate(x => x.DrawText($"({sign}{stats.FullGuildStats.AwardedXp})",
_fonts.NotoSans.CreateFont(_template.User.Xp.Awarded.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.Xp.Awarded.FontSize, FontStyle.Bold),
Brushes.Solid(_template.User.Xp.Awarded.Color), Brushes.Solid(template.User.Xp.Awarded.Color),
pen, pen,
new(awX, awY))); new(awX, awY)));
} }
//ranking //ranking
if (_template.User.GlobalRank.Show) if (template.User.GlobalRank.Show)
img.Mutate(x => x.DrawText(stats.GlobalRanking.ToString(), img.Mutate(x => x.DrawText(stats.GlobalRanking.ToString(),
_fonts.UniSans.CreateFont(_template.User.GlobalRank.FontSize, FontStyle.Bold), _fonts.UniSans.CreateFont(template.User.GlobalRank.FontSize, FontStyle.Bold),
_template.User.GlobalRank.Color, template.User.GlobalRank.Color,
new(_template.User.GlobalRank.Pos.X, _template.User.GlobalRank.Pos.Y))); new(template.User.GlobalRank.Pos.X, template.User.GlobalRank.Pos.Y)));
if (_template.User.GuildRank.Show) if (template.User.GuildRank.Show)
img.Mutate(x => x.DrawText(stats.GuildRanking.ToString(), img.Mutate(x => x.DrawText(stats.GuildRanking.ToString(),
_fonts.UniSans.CreateFont(_template.User.GuildRank.FontSize, FontStyle.Bold), _fonts.UniSans.CreateFont(template.User.GuildRank.FontSize, FontStyle.Bold),
_template.User.GuildRank.Color, template.User.GuildRank.Color,
new(_template.User.GuildRank.Pos.X, _template.User.GuildRank.Pos.Y))); new(template.User.GuildRank.Pos.X, template.User.GuildRank.Pos.Y)));
//time on this level //time on this level
@@ -808,21 +808,21 @@ public class XpService : INService
return string.Format(format, offset.Days, offset.Hours, offset.Minutes); return string.Format(format, offset.Days, offset.Hours, offset.Minutes);
} }
if (_template.User.TimeOnLevel.Global.Show) if (template.User.TimeOnLevel.Global.Show)
img.Mutate(x => x.DrawText(GetTimeSpent(stats.User.LastLevelUp, _template.User.TimeOnLevel.Format), img.Mutate(x => x.DrawText(GetTimeSpent(stats.User.LastLevelUp, template.User.TimeOnLevel.Format),
_fonts.NotoSans.CreateFont(_template.User.TimeOnLevel.Global.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.TimeOnLevel.Global.FontSize, FontStyle.Bold),
_template.User.TimeOnLevel.Global.Color, template.User.TimeOnLevel.Global.Color,
new(_template.User.TimeOnLevel.Global.Pos.X, _template.User.TimeOnLevel.Global.Pos.Y))); new(template.User.TimeOnLevel.Global.Pos.X, template.User.TimeOnLevel.Global.Pos.Y)));
if (_template.User.TimeOnLevel.Guild.Show) if (template.User.TimeOnLevel.Guild.Show)
img.Mutate(x img.Mutate(x
=> x.DrawText(GetTimeSpent(stats.FullGuildStats.LastLevelUp, _template.User.TimeOnLevel.Format), => x.DrawText(GetTimeSpent(stats.FullGuildStats.LastLevelUp, template.User.TimeOnLevel.Format),
_fonts.NotoSans.CreateFont(_template.User.TimeOnLevel.Guild.FontSize, FontStyle.Bold), _fonts.NotoSans.CreateFont(template.User.TimeOnLevel.Guild.FontSize, FontStyle.Bold),
_template.User.TimeOnLevel.Guild.Color, template.User.TimeOnLevel.Guild.Color,
new(_template.User.TimeOnLevel.Guild.Pos.X, _template.User.TimeOnLevel.Guild.Pos.Y))); new(template.User.TimeOnLevel.Guild.Pos.X, template.User.TimeOnLevel.Guild.Pos.Y)));
//avatar //avatar
if (stats.User.AvatarId is not null && _template.User.Icon.Show) if (stats.User.AvatarId is not null && template.User.Icon.Show)
try try
{ {
var avatarUrl = stats.User.RealAvatarUrl(); var avatarUrl = stats.User.RealAvatarUrl();
@@ -836,10 +836,10 @@ public class XpService : INService
using (var tempDraw = Image.Load(avatarData)) using (var tempDraw = Image.Load(avatarData))
{ {
tempDraw.Mutate(x => x tempDraw.Mutate(x => x
.Resize(_template.User.Icon.Size.X, _template.User.Icon.Size.Y) .Resize(template.User.Icon.Size.X, template.User.Icon.Size.Y)
.ApplyRoundedCorners(Math.Max(_template.User.Icon.Size.X, .ApplyRoundedCorners(Math.Max(template.User.Icon.Size.X,
_template.User.Icon.Size.Y) template.User.Icon.Size.Y)
/ 2)); / 2.0f));
await using (var stream = tempDraw.ToStream()) await using (var stream = tempDraw.ToStream())
{ {
data = stream.ToArray(); data = stream.ToArray();
@@ -851,11 +851,11 @@ public class XpService : INService
} }
using var toDraw = Image.Load(data); using var toDraw = Image.Load(data);
if (toDraw.Size() != new Size(_template.User.Icon.Size.X, _template.User.Icon.Size.Y)) if (toDraw.Size() != new Size(template.User.Icon.Size.X, template.User.Icon.Size.Y))
toDraw.Mutate(x => x.Resize(_template.User.Icon.Size.X, _template.User.Icon.Size.Y)); toDraw.Mutate(x => x.Resize(template.User.Icon.Size.X, template.User.Icon.Size.Y));
img.Mutate(x => x.DrawImage(toDraw, img.Mutate(x => x.DrawImage(toDraw,
new Point(_template.User.Icon.Pos.X, _template.User.Icon.Pos.Y), new Point(template.User.Icon.Pos.X, template.User.Icon.Pos.Y),
1)); 1));
} }
catch (Exception ex) catch (Exception ex)
@@ -864,9 +864,9 @@ public class XpService : INService
} }
//club image //club image
if (_template.Club.Icon.Show) await DrawClubImage(img, stats); if (template.Club.Icon.Show) await DrawClubImage(img, stats);
img.Mutate(x => x.Resize(_template.OutputSize.X, _template.OutputSize.Y)); img.Mutate(x => x.Resize(template.OutputSize.X, template.OutputSize.Y));
return ((Stream)img.ToStream(imageFormat), imageFormat); return ((Stream)img.ToStream(imageFormat), imageFormat);
}); });
@@ -880,7 +880,7 @@ public class XpService : INService
var length = info.Length * percent; var length = info.Length * percent;
float x3 = 0, x4 = 0, y3 = 0, y4 = 0; float x3, x4, y3, y4;
if (info.Direction == XpTemplateDirection.Down) if (info.Direction == XpTemplateDirection.Down)
{ {
@@ -936,11 +936,10 @@ public class XpService : INService
using (var tempDraw = Image.Load(imgData)) using (var tempDraw = Image.Load(imgData))
{ {
tempDraw.Mutate(x => x tempDraw.Mutate(x => x
.Resize(_template.Club.Icon.Size.X, _template.Club.Icon.Size.Y) .Resize(template.Club.Icon.Size.X, template.Club.Icon.Size.Y)
.ApplyRoundedCorners(Math.Max(_template.Club.Icon.Size.X, .ApplyRoundedCorners(Math.Max(template.Club.Icon.Size.X,
_template.Club.Icon.Size.Y) template.Club.Icon.Size.Y)
/ 2.0f)); / 2.0f));
;
await using (var tds = tempDraw.ToStream()) await using (var tds = tempDraw.ToStream())
{ {
data = tds.ToArray(); data = tds.ToArray();
@@ -952,12 +951,12 @@ public class XpService : INService
} }
using var toDraw = Image.Load(data); using var toDraw = Image.Load(data);
if (toDraw.Size() != new Size(_template.Club.Icon.Size.X, _template.Club.Icon.Size.Y)) if (toDraw.Size() != new Size(template.Club.Icon.Size.X, template.Club.Icon.Size.Y))
toDraw.Mutate(x => x.Resize(_template.Club.Icon.Size.X, _template.Club.Icon.Size.Y)); toDraw.Mutate(x => x.Resize(template.Club.Icon.Size.X, template.Club.Icon.Size.Y));
img.Mutate(x => x.DrawImage( img.Mutate(x => x.DrawImage(
toDraw, toDraw,
new Point(_template.Club.Icon.Pos.X, _template.Club.Icon.Pos.Y), new Point(template.Club.Icon.Pos.X, template.Club.Icon.Pos.Y),
1)); 1));
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -82,7 +82,7 @@ public class XpTemplateUser
public XpTemplateText GlobalRank { get; set; } public XpTemplateText GlobalRank { get; set; }
public XpTemplateText GuildRank { get; set; } public XpTemplateText GuildRank { get; set; }
public XpTemplateTimeOnLevel TimeOnLevel { get; set; } public XpTemplateTimeOnLevel TimeOnLevel { get; set; }
public XpTemplateXP Xp { get; set; } public XpTemplateXp Xp { get; set; }
} }
public class XpTemplateTimeOnLevel public class XpTemplateTimeOnLevel
@@ -108,7 +108,7 @@ public class XpTemplateText
public XpTemplatePos Pos { get; set; } public XpTemplatePos Pos { get; set; }
} }
public class XpTemplateXP public class XpTemplateXp
{ {
public XpTemplateXpBar Bar { get; set; } public XpTemplateXpBar Bar { get; set; }
public XpTemplateText Global { get; set; } public XpTemplateText Global { get; set; }

View File

@@ -8,8 +8,8 @@ namespace NadekoBot.Services;
public class DbService public class DbService
{ {
private readonly DbContextOptions<NadekoContext> options; private readonly DbContextOptions<NadekoContext> _options;
private readonly DbContextOptions<NadekoContext> migrateOptions; private readonly DbContextOptions<NadekoContext> _migrateOptions;
public DbService(IBotCredentials creds) public DbService(IBotCredentials creds)
{ {
@@ -20,19 +20,19 @@ public class DbService
var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>(); var optionsBuilder = new DbContextOptionsBuilder<NadekoContext>();
optionsBuilder.UseSqlite(builder.ToString()); optionsBuilder.UseSqlite(builder.ToString());
options = optionsBuilder.Options; _options = optionsBuilder.Options;
optionsBuilder = new(); optionsBuilder = new();
optionsBuilder.UseSqlite(builder.ToString()); optionsBuilder.UseSqlite(builder.ToString());
migrateOptions = optionsBuilder.Options; _migrateOptions = optionsBuilder.Options;
} }
public void Setup() public void Setup()
{ {
using var context = new NadekoContext(options); using var context = new NadekoContext(_options);
if (context.Database.GetPendingMigrations().Any()) if (context.Database.GetPendingMigrations().Any())
{ {
var mContext = new NadekoContext(migrateOptions); var mContext = new NadekoContext(_migrateOptions);
mContext.Database.Migrate(); mContext.Database.Migrate();
mContext.SaveChanges(); mContext.SaveChanges();
mContext.Dispose(); mContext.Dispose();
@@ -44,7 +44,7 @@ public class DbService
private NadekoContext GetDbContextInternal() private NadekoContext GetDbContextInternal()
{ {
var context = new NadekoContext(options); var context = new NadekoContext(_options);
context.Database.SetCommandTimeout(60); context.Database.SetCommandTimeout(60);
var conn = context.Database.GetDbConnection(); var conn = context.Database.GetDbConnection();
conn.Open(); conn.Open();

View File

@@ -3,7 +3,7 @@ using Google.Apis.Customsearch.v1.Data;
namespace NadekoBot.Services; namespace NadekoBot.Services;
public interface IGoogleApiService : INService public interface IGoogleApiService
{ {
IReadOnlyDictionary<string, string> Languages { get; } IReadOnlyDictionary<string, string> Languages { get; }