From 5dd55bbc0a10221f9bdb00716c02fd08038c749a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 30 Aug 2016 00:00:19 +0200 Subject: [PATCH] Added as much gambling as possible without drawing --- ...er.cs => 20160829215759_first.Designer.cs} | 2 +- ...53124_first.cs => 20160829215759_first.cs} | 0 .../Commands/MessageRepeater.cs | 53 +++-- .../Modules/Gambling/Commands/AnimalRacing.cs | 23 +- .../Gambling/Commands/DiceRollCommand.cs | 171 +++++++------- .../Gambling/Commands/FlipCoinCommand.cs | 182 +++++++-------- src/NadekoBot/Modules/Gambling/Gambling.cs | 208 ++++++++++-------- .../Games/Commands/PlantAndPickCommands.cs | 20 +- src/NadekoBot/Modules/Music/Classes/Song.cs | 9 +- .../Modules/Music/Classes/SongBuffer.cs | 30 +-- src/NadekoBot/Services/CurrencyHandler.cs | 51 +++++ .../Services/Database/Models/Currency.cs | 14 ++ .../Repositories/ICurrencyRepository.cs | 17 ++ .../Repositories/Impl/CurrencyRepository.cs | 60 +++++ src/NadekoBot/Services/Database/UnitOfWork.cs | 3 + 15 files changed, 491 insertions(+), 352 deletions(-) rename src/NadekoBot/Migrations/{20160828153124_first.Designer.cs => 20160829215759_first.Designer.cs} (99%) rename src/NadekoBot/Migrations/{20160828153124_first.cs => 20160829215759_first.cs} (100%) create mode 100644 src/NadekoBot/Services/CurrencyHandler.cs create mode 100644 src/NadekoBot/Services/Database/Models/Currency.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/ICurrencyRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/CurrencyRepository.cs diff --git a/src/NadekoBot/Migrations/20160828153124_first.Designer.cs b/src/NadekoBot/Migrations/20160829215759_first.Designer.cs similarity index 99% rename from src/NadekoBot/Migrations/20160828153124_first.Designer.cs rename to src/NadekoBot/Migrations/20160829215759_first.Designer.cs index 9b60ffb2..f15cb84e 100644 --- a/src/NadekoBot/Migrations/20160828153124_first.Designer.cs +++ b/src/NadekoBot/Migrations/20160829215759_first.Designer.cs @@ -8,7 +8,7 @@ using NadekoBot.Services.Database.Impl; namespace NadekoBot.Migrations { [DbContext(typeof(NadekoSqliteContext))] - [Migration("20160828153124_first")] + [Migration("20160829215759_first")] partial class first { protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/src/NadekoBot/Migrations/20160828153124_first.cs b/src/NadekoBot/Migrations/20160829215759_first.cs similarity index 100% rename from src/NadekoBot/Migrations/20160828153124_first.cs rename to src/NadekoBot/Migrations/20160829215759_first.cs diff --git a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs index 16d87b48..04b2dcea 100644 --- a/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs +++ b/src/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs @@ -30,10 +30,10 @@ namespace NadekoBot.Modules.Administration public Repeater Repeater { get; } public ITextChannel Channel { get; } - public RepeatRunner(Repeater repeater) + public RepeatRunner(Repeater repeater, ITextChannel channel = null) { this.Repeater = repeater; - this.Channel = NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); + this.Channel = channel ?? NadekoBot.Client.GetGuild(repeater.GuildId)?.GetTextChannel(repeater.ChannelId); if (Channel == null) return; Task.Run(Run); @@ -89,36 +89,42 @@ namespace NadekoBot.Modules.Administration return; } rep.Reset(); - await channel.SendMessageAsync("πŸ”„ " + rep.Repeater.Message); + await channel.SendMessageAsync("πŸ”„ " + rep.Repeater.Message).ConfigureAwait(false); } [LocalizedCommand, LocalizedDescription, LocalizedSummary] [RequireContext(ContextType.Guild)] - public async Task Repeat(IUserMessage imsg, int minutes, [Remainder] string message = null) + public async Task Repeat(IUserMessage imsg) + { + var channel = (ITextChannel)imsg.Channel; + RepeatRunner rep; + if (repeaters.TryRemove(channel.Id, out rep)) + { + using (var uow = DbHandler.UnitOfWork()) + { + uow.Repeaters.Remove(rep.Repeater); + await uow.CompleteAsync(); + } + rep.Stop(); + await channel.SendMessageAsync("`Stopped repeating a message.`").ConfigureAwait(false); + } + else + await channel.SendMessageAsync("`No message is repeating.`").ConfigureAwait(false); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Repeat(IUserMessage imsg, int minutes, [Remainder] string message) { var channel = (ITextChannel)imsg.Channel; if (minutes < 1 || minutes > 1500) return; - RepeatRunner rep; - - if (string.IsNullOrWhiteSpace(message)) //turn off - { - if (repeaters.TryRemove(channel.Id, out rep)) - { - using (var uow = DbHandler.UnitOfWork()) - { - uow.Repeaters.Remove(rep.Repeater); - await uow.CompleteAsync(); - } - rep.Stop(); - await channel.SendMessageAsync("`Stopped repeating a message.`").ConfigureAwait(false); - } - else - await channel.SendMessageAsync("`No message is repeating.`").ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(message)) return; - } + + RepeatRunner rep; rep = repeaters.AddOrUpdate(channel.Id, (cid) => { @@ -133,7 +139,7 @@ namespace NadekoBot.Modules.Administration }; uow.Repeaters.Add(localRep); uow.Complete(); - return new RepeatRunner(localRep); + return new RepeatRunner(localRep, channel); } }, (cid, old) => { @@ -147,8 +153,9 @@ namespace NadekoBot.Modules.Administration old.Reset(); return old; }); - } + await channel.SendMessageAsync($"Repeating \"{rep.Repeater.Message}\" every {rep.Repeater.Interval} minutes").ConfigureAwait(false); + } } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 79f496ec..7aece0bc 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -41,17 +41,10 @@ namespace NadekoBot.Modules.Gambling if (amount < 0) amount = 0; - //todo DB - //var userFlowers = Gambling.GetUserFlowers(umsg.Author.Id); + if (amount > 0) + if(!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)umsg.Author, "BetRace", amount, true).ConfigureAwait(false)) + await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {Gambling.CurrencyName}s.").ConfigureAwait(false); - //if (userFlowers < amount) - //{ - // await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false); - // return; - //} - - //if (amount > 0) - // await FlowersHandler.RemoveFlowers(umsg.Author, "BetRace", (int)amount, true).ConfigureAwait(false); AnimalRace ar; if (!AnimalRaces.TryGetValue(channel.Guild.Id, out ar)) @@ -116,9 +109,9 @@ namespace NadekoBot.Modules.Gambling { await raceChannel.SendMessageAsync("🏁`Race failed to start since there was not enough participants.`"); var p = participants.FirstOrDefault(); - //todo DB - //if (p != null) - // await FlowersHandler.AddFlowersAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false); + + if (p != null) + await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false); End(); return; } @@ -191,8 +184,8 @@ namespace NadekoBot.Modules.Gambling if (winner.AmountBet > 0) { var wonAmount = winner.AmountBet * (participants.Count - 1); - //todo DB - //await FlowersHandler.AddFlowersAsync(winner.User, "Won a Race", wonAmount).ConfigureAwait(false); + + await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, false).ConfigureAwait(false); await raceChannel.SendMessageAsync($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{CurrencySign}!**").ConfigureAwait(false); } else diff --git a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs index 9741fa97..c3e9d9ed 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/DiceRollCommand.cs @@ -13,97 +13,98 @@ namespace NadekoBot.Modules.Gambling public partial class Gambling { private Regex dndRegex { get; } = new Regex(@"(?\d+)d(?\d+)", RegexOptions.Compiled); - ////todo drawing - //[LocalizedCommand, LocalizedDescription, LocalizedSummary] - //[RequireContext(ContextType.Guild)] - //public Task Roll(IUserMessage umsg, [Remainder] string arg = null) => - // InternalRoll(umsg, arg, true); - //[LocalizedCommand, LocalizedDescription, LocalizedSummary] - //[RequireContext(ContextType.Guild)] - //public Task Rolluo(IUserMessage umsg, [Remainder] string arg = null) => - // InternalRoll(umsg, arg, false); + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public Task Roll(IUserMessage umsg, [Remainder] string arg = null) => + InternalRoll(umsg, arg, true); - //private async Task InternalRoll(IUserMessage umsg, string arg, bool ordered) { - // var channel = (ITextChannel)umsg.Channel; - // var r = new Random(); - // if (string.IsNullOrWhiteSpace(arg)) - // { - // var gen = r.Next(0, 101); + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public Task Rolluo(IUserMessage umsg, [Remainder] string arg = null) => + InternalRoll(umsg, arg, false); + //todo drawing + private async Task InternalRoll(IUserMessage umsg, string arg, bool ordered) + { + var channel = (ITextChannel)umsg.Channel; + var r = new Random(); + //if (string.IsNullOrWhiteSpace(arg)) + //{ + // var gen = r.Next(0, 101); - // var num1 = gen / 10; - // var num2 = gen % 10; + // var num1 = gen / 10; + // var num2 = gen % 10; - // var imageStream = await new Image[2] { GetDice(num1), GetDice(num2) }.Merge().ToStream(ImageFormat.Png); + // var imageStream = await new Image[2] { GetDice(num1), GetDice(num2) }.Merge().ToStream(ImageFormat.Png); - // await channel.SendFileAsync(imageStream, "dice.png").ConfigureAwait(false); - // return; - // } - // Match m; - // if ((m = dndRegex.Match(arg)).Length != 0) - // { - // int n1; - // int n2; - // if (int.TryParse(m.Groups["n1"].ToString(), out n1) && - // int.TryParse(m.Groups["n2"].ToString(), out n2) && - // n1 <= 50 && n2 <= 100000 && n1 > 0 && n2 > 0) - // { - // var arr = new int[n1]; - // for (int i = 0; i < n1; i++) - // { - // arr[i] = r.Next(1, n2 + 1); - // } - // var elemCnt = 0; - // await channel.SendMessageAsync($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false); - // } - // return; - // } - // try - // { - // var num = int.Parse(e.Args[0]); - // if (num < 1) num = 1; - // if (num > 30) - // { - // await channel.SendMessageAsync("You can roll up to 30 dice at a time.").ConfigureAwait(false); - // num = 30; - // } - // var dices = new List(num); - // var values = new List(num); - // for (var i = 0; i < num; i++) - // { - // var randomNumber = r.Next(1, 7); - // var toInsert = dices.Count; - // if (ordered) - // { - // if (randomNumber == 6 || dices.Count == 0) - // toInsert = 0; - // else if (randomNumber != 1) - // for (var j = 0; j < dices.Count; j++) - // { - // if (values[j] < randomNumber) - // { - // toInsert = j; - // break; - // } - // } - // } - // else - // { - // toInsert = dices.Count; - // } - // dices.Insert(toInsert, GetDice(randomNumber)); - // values.Insert(toInsert, randomNumber); - // } + // await channel.SendFileAsync(imageStream, "dice.png").ConfigureAwait(false); + // return; + //} + Match m; + if ((m = dndRegex.Match(arg)).Length != 0) + { + int n1; + int n2; + if (int.TryParse(m.Groups["n1"].ToString(), out n1) && + int.TryParse(m.Groups["n2"].ToString(), out n2) && + n1 <= 50 && n2 <= 100000 && n1 > 0 && n2 > 0) + { + var arr = new int[n1]; + for (int i = 0; i < n1; i++) + { + arr[i] = r.Next(1, n2 + 1); + } + var elemCnt = 0; + await channel.SendMessageAsync($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false); + } + return; + } + //try + //{ + // var num = int.Parse(e.Args[0]); + // if (num < 1) num = 1; + // if (num > 30) + // { + // await channel.SendMessageAsync("You can roll up to 30 dice at a time.").ConfigureAwait(false); + // num = 30; + // } + // var dices = new List(num); + // var values = new List(num); + // for (var i = 0; i < num; i++) + // { + // var randomNumber = r.Next(1, 7); + // var toInsert = dices.Count; + // if (ordered) + // { + // if (randomNumber == 6 || dices.Count == 0) + // toInsert = 0; + // else if (randomNumber != 1) + // for (var j = 0; j < dices.Count; j++) + // { + // if (values[j] < randomNumber) + // { + // toInsert = j; + // break; + // } + // } + // } + // else + // { + // toInsert = dices.Count; + // } + // dices.Insert(toInsert, GetDice(randomNumber)); + // values.Insert(toInsert, randomNumber); + // } - // var bitmap = dices.Merge(); - // await channel.SendMessageAsync(values.Count + " Dice rolled. Total: **" + values.Sum() + "** Average: **" + (values.Sum() / (1.0f * values.Count)).ToString("N2") + "**").ConfigureAwait(false); - // await channel.SendFileAsync("dice.png", bitmap.ToStream(ImageFormat.Png)).ConfigureAwait(false); - // } - // catch - // { - // await channel.SendMessageAsync("Please enter a number of dice to roll.").ConfigureAwait(false); - // } - //} + // var bitmap = dices.Merge(); + // await channel.SendMessageAsync(values.Count + " Dice rolled. Total: **" + values.Sum() + "** Average: **" + (values.Sum() / (1.0f * values.Count)).ToString("N2") + "**").ConfigureAwait(false); + // await channel.SendFileAsync("dice.png", bitmap.ToStream(ImageFormat.Png)).ConfigureAwait(false); + //} + //catch + //{ + // await channel.SendMessageAsync("Please enter a number of dice to roll.").ConfigureAwait(false); + //} + } [LocalizedCommand, LocalizedDescription, LocalizedSummary] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs index 9f30701f..2afca817 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlipCoinCommand.cs @@ -1,113 +1,93 @@ -//using Discord.Commands; -//using NadekoBot.Classes; -//using NadekoBot.Extensions; -//using System; -//using System.Drawing; -//using System.Threading.Tasks; +using Discord; +using Discord.Commands; -////todo drawing -//namespace NadekoBot.Modules.Gambling -//{ -// internal class FlipCoinCommand : DiscordCommand -// { +//todo drawing +namespace NadekoBot.Modules.Gambling +{ + [Group] + public class FlipCoinCommands + { -// public FlipCoinCommand(DiscordModule module) : base(module) { } - -// internal override void Init(CommandGroupBuilder cgb) -// { -// cgb.CreateCommand(Module.Prefix + "flip") -// .Description($"Flips coin(s) - heads or tails, and shows an image. | `{Prefix}flip` or `{Prefix}flip 3`") -// .Parameter("count", ParameterType.Optional) -// .Do(FlipCoinFunc()); - -// cgb.CreateCommand(Module.Prefix + "betflip") -// .Alias(Prefix+"bf") -// .Description($"Bet to guess will the result be heads or tails. Guessing award you double flowers you've bet. | `{Prefix}bf 5 heads` or `{Prefix}bf 3 t`") -// .Parameter("amount", ParameterType.Required) -// .Parameter("guess", ParameterType.Required) -// .Do(BetFlipCoinFunc()); -// } + public FlipCoinCommands() { } + ////todo drawing + //[LocalizedCommand, LocalizedDescription, LocalizedSummary] + //[RequireContext(ContextType.Guild)] + //public async Task Flip(IUserMessage imsg, int count = 0) + //{ + // var channel = (ITextChannel)imsg.Channel; + // if (count == 0) + // { + // if (rng.Next(0, 2) == 1) + // await channel.SendFileAsync("heads.png", ).ConfigureAwait(false); + // else + // await channel.SendFileAsync("tails.png", ).ConfigureAwait(false); + // return; + // } + // if (result > 10) + // result = 10; + // var imgs = new Image[result]; + // for (var i = 0; i < result; i++) + // { + // imgs[i] = rng.Next(0, 2) == 0 ? + // Properties.Resources.tails : + // Properties.Resources.heads; + // } + // await channel.SendFile($"{result} coins.png", imgs.Merge().ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); + // return; + // await channel.SendMessageAsync("Invalid number").ConfigureAwait(false); + //} -// private readonly Random rng = new Random(); -// public Func BetFlipCoinFunc() => async e => -// { + //[LocalizedCommand, LocalizedDescription, LocalizedSummary] + //[RequireContext(ContextType.Guild)] + //public async Task Betflip(IUserMessage umsg, int amount, string guess) + //{ + // var channel = (ITextChannel)umsg.Channel; + // var guildUser = (IGuildUser)umsg.Author; + // var guessStr = guess.Trim().ToUpperInvariant(); + // if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS") + // return; + + // if (amount < 1) + // return; -// var amountstr = amount.Trim(); + // var userFlowers = Gambling.GetUserFlowers(umsg.Author.Id); -// var guessStr = guess.Trim().ToUpperInvariant(); -// if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS") -// return; + // if (userFlowers < amount) + // { + // await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {Gambling.CurrencyName}s. You only have {userFlowers}{Gambling.CurrencySign}.").ConfigureAwait(false); + // return; + // } -// int amount; -// if (!int.TryParse(amountstr, out amount) || amount < 1) -// return; + // await CurrencyHandler.RemoveCurrencyAsync(guildUser, "Betflip Gamble", amount, false).ConfigureAwait(false); + // //heads = true + // //tails = false -// var userFlowers = Gambling.GetUserFlowers(umsg.Author.Id); + // var isHeads = guessStr == "HEADS" || guessStr == "H"; + // bool result = false; + // var rng = new Random(); + // if (rng.Next(0, 2) == 1) + // { + // await channel.SendFileAsync("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); + // result = true; + // } + // else + // { + // await channel.SendFileAsync("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); + // } -// if (userFlowers < amount) -// { -// await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false); -// return; -// } + // string str; + // if (isHeads == result) + // { + // str = $"{umsg.Author.Mention}`You guessed it!` You won {amount * 2}{Gambling.CurrencySign}"; + // await CurrencyHandler.AddCurrencyAsync((IGuildUser)umsg.Author, "Betflip Gamble", amount * 2, false).ConfigureAwait(false); -// await FlowersHandler.RemoveFlowers(umsg.Author, "Betflip Gamble", (int)amount, true).ConfigureAwait(false); -// //heads = true -// //tails = false + // } + // else + // str = $"{umsg.Author.Mention}`More luck next time.`"; -// var guess = guessStr == "HEADS" || guessStr == "H"; -// bool result = false; -// if (rng.Next(0, 2) == 1) { -// await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); -// result = true; -// } -// else { -// await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); -// } - -// string str; -// if (guess == result) -// { -// str = $"{umsg.Author.Mention}`You guessed it!` You won {amount * 2}{NadekoBot.Config.CurrencySign}"; -// await FlowersHandler.AddFlowersAsync(umsg.Author, "Betflip Gamble", amount * 2, true).ConfigureAwait(false); - -// } -// else -// str = $"{umsg.Author.Mention}`More luck next time.`"; - -// await channel.SendMessageAsync(str).ConfigureAwait(false); -// }; - -// public Func FlipCoinFunc() => async e => -// { - -// if (count == "") -// { -// if (rng.Next(0, 2) == 1) -// await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); -// else -// await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); -// } -// else -// { -// int result; -// if (int.TryParse(count, out result)) -// { -// if (result > 10) -// result = 10; -// var imgs = new Image[result]; -// for (var i = 0; i < result; i++) -// { -// imgs[i] = rng.Next(0, 2) == 0 ? -// Properties.Resources.tails : -// Properties.Resources.heads; -// } -// await e.Channel.SendFile($"{result} coins.png", imgs.Merge().ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false); -// return; -// } -// await channel.SendMessageAsync("Invalid number").ConfigureAwait(false); -// } -// }; -// } -//} + // await channel.SendMessageAsync(str).ConfigureAwait(false); + //} + } +} diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 87a07fab..3632827a 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -9,6 +9,8 @@ using System.Threading.Tasks; using NadekoBot.Services; using Discord.WebSocket; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using System.Collections.Generic; //todo DB namespace NadekoBot.Modules.Gambling @@ -45,44 +47,50 @@ namespace NadekoBot.Modules.Gambling var membersArray = members as IUser[] ?? members.ToArray(); var usr = membersArray[new Random().Next(0, membersArray.Length)]; await channel.SendMessageAsync($"**Raffled user:** {usr.Username} (id: {usr.Id})").ConfigureAwait(false); - } + + [LocalizedCommand("$$$"), LocalizedDescription("$$$"), LocalizedSummary("$$$")] + [RequireContext(ContextType.Guild)] + public async Task Cash(IUserMessage umsg, [Remainder] IUser user = null) + { + var channel = (ITextChannel)umsg.Channel; - ////todo DB - //[LocalizedCommand("$$$"), LocalizedDescription("$$$"), LocalizedSummary("$$$")] - //[RequireContext(ContextType.Guild)] - //public async Task Cash(IUserMessage umsg, [Remainder] string arg) - //{ - // var channel = (ITextChannel)umsg.Channel; + user = user ?? umsg.Author; + long amount; + BotConfig config; + using (var uow = DbHandler.UnitOfWork()) + { + amount = uow.Currency.GetUserCurrency(user.Id); + config = uow.BotConfig.GetOrCreate(); + } - // var usr = e.Message.MentionedUsers.FirstOrDefault() ?? umsg.Author; - // var pts = GetUserFlowers(usr.Id); - // var str = $"{usr.Name} has {pts} {NadekoBot.Config.CurrencySign}"; - // await channel.SendMessageAsync(str).ConfigureAwait(false); - //} + await channel.SendMessageAsync($"{user.Username} has {amount} {config.CurrencySign}").ConfigureAwait(false); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Give(IUserMessage umsg, long amount, [Remainder] IUser receiver) + { + var channel = (ITextChannel)umsg.Channel; + if (amount <= 0) + return; + bool success = false; + using (var uow = DbHandler.UnitOfWork()) + { + success = uow.Currency.TryUpdateState(umsg.Author.Id, amount); + if(success) + uow.Currency.TryUpdateState(umsg.Author.Id, amount); - ////todo DB - //[LocalizedCommand, LocalizedDescription, LocalizedSummary] - //[RequireContext(ContextType.Guild)] - //public async Task Give(IUserMessage umsg, long amount, [Remainder] IUser receiver) - //{ - // var channel = (ITextChannel)umsg.Channel; - // if (amount <= 0) - // return; - // var userFlowers = GetUserFlowers(umsg.Author.Id); + await uow.CompleteAsync(); + } + if (!success) + { + await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {Gambling.CurrencyPluralName}s.").ConfigureAwait(false); + return; + } - // if (userFlowers < amount) - // { - // await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false); - // return; - // } - - // await FlowersHandler.RemoveFlowers(umsg.Author, "Gift", (int)amount, true).ConfigureAwait(false); - // await FlowersHandler.AddFlowersAsync(receiver, "Gift", (int)amount).ConfigureAwait(false); - - // await channel.SendMessageAsync($"{umsg.Author.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {receiver.Mention}!").ConfigureAwait(false); - - //} + await channel.SendMessageAsync($"{umsg.Author.Mention} successfully sent {amount} {Gambling.CurrencyPluralName}s to {receiver.Mention}!").ConfigureAwait(false); + } ////todo DB ////todo owner only @@ -100,9 +108,9 @@ namespace NadekoBot.Modules.Gambling // if (amount <= 0) // return; - // await FlowersHandler.AddFlowersAsync(usrId, $"Awarded by bot owner. ({umsg.Author.Username}/{umsg.Author.Id})", (int)amount).ConfigureAwait(false); + // await CurrencyHandler.AddFlowersAsync(usrId, $"Awarded by bot owner. ({umsg.Author.Username}/{umsg.Author.Id})", (int)amount).ConfigureAwait(false); - // await channel.SendMessageAsync($"{umsg.Author.Mention} successfully awarded {amount} {NadekoBot.Config.CurrencyName}s to <@{usrId}>!").ConfigureAwait(false); + // await channel.SendMessageAsync($"{umsg.Author.Mention} successfully awarded {amount} {Gambling.CurrencyName}s to <@{usrId}>!").ConfigureAwait(false); //} ////todo owner only @@ -112,6 +120,7 @@ namespace NadekoBot.Modules.Gambling //public Task Take(IUserMessage umsg, long amount, [Remainder] IGuildUser user) => // Take(umsg, amount, user.Id); + //todo owner only //[LocalizedCommand, LocalizedDescription, LocalizedSummary] //[RequireContext(ContextType.Guild)] //public async Task Take(IUserMessage umsg, long amount, [Remainder] ulong usrId) @@ -120,76 +129,85 @@ namespace NadekoBot.Modules.Gambling // if (amount <= 0) // return; - // await FlowersHandler.RemoveFlowers(usrId, $"Taken by bot owner.({umsg.Author.Username}/{umsg.Author.Id})", (int)amount).ConfigureAwait(false); + // await CurrencyHandler.RemoveFlowers(usrId, $"Taken by bot owner.({umsg.Author.Username}/{umsg.Author.Id})", (int)amount).ConfigureAwait(false); - // await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {NadekoBot.Config.CurrencyName}s from <@{usrId}>!").ConfigureAwait(false); + // await channel.SendMessageAsync($"{umsg.Author.Mention} successfully took {amount} {Gambling.CurrencyName}s from <@{usrId}>!").ConfigureAwait(false); //} - //[LocalizedCommand, LocalizedDescription, LocalizedSummary] - //[RequireContext(ContextType.Guild)] - //public async Task BetRoll(IUserMessage umsg, int amount) - //{ - // var channel = (ITextChannel)umsg.Channel; + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task BetRoll(IUserMessage umsg, long amount) + { + var channel = (ITextChannel)umsg.Channel; - // if (amount < 1) - // return; + if (amount < 1) + return; - // var userFlowers = GetUserFlowers(umsg.Author.Id); + var guildUser = (IGuildUser)umsg.Author; - // if (userFlowers < amount) - // { - // await channel.SendMessageAsync($"{umsg.Author.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false); - // return; - // } + long userFlowers; + using (var uow = DbHandler.UnitOfWork()) + { + userFlowers = uow.Currency.GetOrCreate(umsg.Id).Amount; + } - // await FlowersHandler.RemoveFlowers(umsg.Author, "Betroll Gamble", (int)amount, true).ConfigureAwait(false); + if (userFlowers < amount) + { + await channel.SendMessageAsync($"{guildUser.Mention} You don't have enough {Gambling.CurrencyName}s. You only have {userFlowers}{Gambling.CurrencySign}.").ConfigureAwait(false); + return; + } - // var rng = new Random().Next(0, 101); - // var str = $"{umsg.Author.Mention} `You rolled {rng}.` "; - // if (rng < 67) - // { - // str += "Better luck next time."; - // } - // else if (rng < 90) - // { - // str += $"Congratulations! You won {amount * 2}{NadekoBot.Config.CurrencySign} for rolling above 66"; - // await FlowersHandler.AddFlowersAsync(umsg.Author, "Betroll Gamble", amount * 2, true).ConfigureAwait(false); - // } - // else if (rng < 100) - // { - // str += $"Congratulations! You won {amount * 3}{NadekoBot.Config.CurrencySign} for rolling above 90."; - // await FlowersHandler.AddFlowersAsync(umsg.Author, "Betroll Gamble", amount * 3, true).ConfigureAwait(false); - // } - // else - // { - // str += $"πŸ‘‘ Congratulations! You won {amount * 10}{NadekoBot.Config.CurrencySign} for rolling **100**. πŸ‘‘"; - // await FlowersHandler.AddFlowersAsync(umsg.Author, "Betroll Gamble", amount * 10, true).ConfigureAwait(false); - // } + await CurrencyHandler.RemoveCurrencyAsync(guildUser, "Betroll Gamble", amount, false).ConfigureAwait(false); - // await channel.SendMessageAsync(str).ConfigureAwait(false); - //} + var rng = new Random().Next(0, 101); + var str = $"{guildUser.Mention} `You rolled {rng}.` "; + if (rng < 67) + { + str += "Better luck next time."; + } + else if (rng < 90) + { + str += $"Congratulations! You won {amount * 2}{Gambling.CurrencySign} for rolling above 66"; + await CurrencyHandler.AddCurrencyAsync(guildUser, "Betroll Gamble", amount * 2, false).ConfigureAwait(false); + } + else if (rng < 100) + { + str += $"Congratulations! You won {amount * 3}{Gambling.CurrencySign} for rolling above 90."; + await CurrencyHandler.AddCurrencyAsync(guildUser, "Betroll Gamble", amount * 3, false).ConfigureAwait(false); + } + else + { + str += $"πŸ‘‘ Congratulations! You won {amount * 10}{Gambling.CurrencySign} for rolling **100**. πŸ‘‘"; + await CurrencyHandler.AddCurrencyAsync(guildUser, "Betroll Gamble", amount * 10, false).ConfigureAwait(false); + } - ////todo DB -// [LocalizedCommand, LocalizedDescription, LocalizedSummary] -// [RequireContext(ContextType.Guild)] -// public async Task Leaderboard(IUserMessage umsg) -// { -// var channel = (ITextChannel)umsg.Channel; + await channel.SendMessageAsync(str).ConfigureAwait(false); + } -// var richestTemp = DbHandler.Instance.GetTopRichest(); -// var richest = richestTemp as CurrencyState[] ?? richestTemp.ToArray(); -// if (richest.Length == 0) -// return; -// await channel.SendMessageAsync( -// richest.Aggregate(new StringBuilder( -//$@"```xl -//┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓ -//┃ Id ┃ $$$ ┃ -//"), -// (cur, cs) => cur.AppendLine( -//$@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫ -//┃{(e.Server.Users.Where(u => u.Id == (ulong)cs.UserId).FirstOrDefault()?.Name.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs.Value,5} ┃") -// ).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false); - //} + //todo DB + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Leaderboard(IUserMessage umsg) + { + var channel = (ITextChannel)umsg.Channel; + + IEnumerable richest; + using (var uow = DbHandler.UnitOfWork()) + { + richest = uow.Currency.GetTopRichest(10); + } + if (!richest.Any()) + return; + await channel.SendMessageAsync( + richest.Aggregate(new StringBuilder( +$@"```xl + ┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓ + ┃ Id ┃ $$$ ┃ + "), + (cur, cs) => cur.AppendLine( +$@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫ + ┃{(channel.Guild.GetUser(cs.UserId)?.Username.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs,5} ┃") + ).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false); + } } } diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 6b144495..6f1aff9d 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -51,7 +51,7 @@ // var rnd = Math.Abs(rng.Next(0,101)); // if (rnd == 0) // { -// var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await channel.SendMessageAsync($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`") }; +// var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await channel.SendMessageAsync($"❗ A random {Gambling.CurrencyName} appeared! Pick it up by typing `>pick`") }; // plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msgs, (u, m) => { m.ForEach(async msgToDelete => { try { await msgToDelete.Delete(); } catch { } }); return msgs; }); // plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now); // } @@ -79,8 +79,8 @@ // foreach(var msgToDelete in msgs) // await msgToDelete.Delete().ConfigureAwait(false); -// await FlowersHandler.AddFlowersAsync(umsg.Author, "Picked a flower.", 1, true).ConfigureAwait(false); -// var msg = await channel.SendMessageAsync($"**{umsg.Author.Username}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false); +// await CurrencyHandler.AddFlowersAsync(umsg.Author, "Picked a flower.", 1, true).ConfigureAwait(false); +// var msg = await channel.SendMessageAsync($"**{umsg.Author.Username}** picked a {Gambling.CurrencyName}!").ConfigureAwait(false); // ThreadPool.QueueUserWorkItem(async (state) => // { // try @@ -101,24 +101,24 @@ // { // if (plantedFlowerChannels.ContainsKey(e.Channel.Id)) // { -// await channel.SendMessageAsync($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false); +// await channel.SendMessageAsync($"There is already a {Gambling.CurrencyName} in this channel.").ConfigureAwait(false); // return; // } -// var removed = await FlowersHandler.RemoveFlowers(umsg.Author, "Planted a flower.", 1, true).ConfigureAwait(false); +// var removed = await CurrencyHandler.RemoveFlowers(umsg.Author, "Planted a flower.", 1, true).ConfigureAwait(false); // if (!removed) // { -// await channel.SendMessageAsync($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false); +// await channel.SendMessageAsync($"You don't have any {Gambling.CurrencyName}s.").ConfigureAwait(false); // return; // } // var file = GetRandomCurrencyImagePath(); // Message msg; // if (file == null) -// msg = await channel.SendMessageAsync(NadekoBot.Config.CurrencySign).ConfigureAwait(false); +// msg = await channel.SendMessageAsync(Gambling.CurrencySign).ConfigureAwait(false); // else // msg = await e.Channel.SendFile(file).ConfigureAwait(false); -// var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]); -// var msg2 = await channel.SendMessageAsync($"Oh how Nice! **{umsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false); +// var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.CurrencyName[0]); +// var msg2 = await channel.SendMessageAsync($"Oh how Nice! **{umsg.Author.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false); // plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 }); // } // finally { locker.Release(); } @@ -126,7 +126,7 @@ // cgb.CreateCommand(Prefix + "gencurrency") // .Alias(Prefix + "gc") -// .Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `{Prefix}gc` or `{Prefix}gc 60`") +// .Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {Gambling.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `{Prefix}gc` or `{Prefix}gc 60`") // .AddCheck(SimpleCheckers.ManageMessages()) // .Parameter("cd", ParameterType.Unparsed) // .Do(async e => diff --git a/src/NadekoBot/Modules/Music/Classes/Song.cs b/src/NadekoBot/Modules/Music/Classes/Song.cs index f6827d2a..9ec3c1db 100644 --- a/src/NadekoBot/Modules/Music/Classes/Song.cs +++ b/src/NadekoBot/Modules/Music/Classes/Song.cs @@ -84,7 +84,7 @@ namespace NadekoBot.Modules.Music.Classes { var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); - SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo); + SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo, frameBytes * 100); var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false); bytesSent = 0; @@ -118,9 +118,10 @@ namespace NadekoBot.Modules.Music.Classes while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); - var read = inStream.Read(buffer, 0, buffer.Length); + var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); //await inStream.CopyToAsync(voiceClient.OutputStream); - _log.Debug("read {0}", read); + if(read < frameBytes) + _log.Debug("read {0}", read); unchecked { bytesSent += (ulong)read; @@ -155,7 +156,7 @@ namespace NadekoBot.Modules.Music.Classes int delayMillis = unchecked(nextTime - Environment.TickCount); if (delayMillis > 0) await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false); - await outStream.WriteAsync(buffer, 0, read); + await outStream.WriteAsync(buffer, 0, read).ConfigureAwait(false); } } finally diff --git a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs index a53d7d0b..0979f504 100644 --- a/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs +++ b/src/NadekoBot/Modules/Music/Classes/SongBuffer.cs @@ -1,4 +1,5 @@ ο»Ώusing NadekoBot.Extensions; +using NLog; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -17,14 +18,15 @@ namespace NadekoBot.Modules.Music.Classes /// class SongBuffer : Stream { - - public SongBuffer(MusicPlayer musicPlayer, string basename, SongInfo songInfo, int skipTo) + public SongBuffer(MusicPlayer musicPlayer, string basename, SongInfo songInfo, int skipTo, int maxFileSize) { MusicPlayer = musicPlayer; Basename = basename; SongInfo = songInfo; SkipTo = skipTo; + MaxFileSize = maxFileSize; CurrentFileStream = new FileStream(this.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); + _log = LogManager.GetCurrentClassLogger(); } MusicPlayer MusicPlayer; @@ -35,7 +37,7 @@ namespace NadekoBot.Modules.Music.Classes private int SkipTo; - private static int MAX_FILE_SIZE = 2.MiB(); + private int MaxFileSize = 2.MiB(); private long FileNumber = -1; @@ -46,9 +48,10 @@ namespace NadekoBot.Modules.Music.Classes private ulong CurrentBufferSize = 0; private FileStream CurrentFileStream; + private Logger _log; public Task BufferSong(CancellationToken cancelToken) => - Task.Factory.StartNew(async () => + Task.Run(async () => { Process p = null; FileStream outStream = null; @@ -72,7 +75,7 @@ namespace NadekoBot.Modules.Music.Classes while (!p.HasExited) //Also fix low bandwidth { int bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false); - if (currentFileSize >= MAX_FILE_SIZE) + if (currentFileSize >= MaxFileSize) { try { @@ -122,7 +125,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: p.Dispose(); } } - }, TaskCreationOptions.LongRunning); + }); /// /// Return the next file to read, and delete the old one @@ -172,18 +175,7 @@ Check the guides for your platform on how to setup ffmpeg correctly: public override long Length => (long) CurrentBufferSize; - public override long Position - { - get - { - return 0; - } - - set - { - - } - } + public override long Position { get; set; } = 0; public override void Flush() { } @@ -198,6 +190,8 @@ Check the guides for your platform on how to setup ffmpeg correctly: CurrentFileStream = new FileStream(GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); read += CurrentFileStream.Read(buffer, read + offset, count - read); } + if (read < count) + Array.Clear(buffer, read, count - read); } return read; } diff --git a/src/NadekoBot/Services/CurrencyHandler.cs b/src/NadekoBot/Services/CurrencyHandler.cs new file mode 100644 index 00000000..d86eea80 --- /dev/null +++ b/src/NadekoBot/Services/CurrencyHandler.cs @@ -0,0 +1,51 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord; +using NadekoBot.Services.Database; +using NadekoBot.Extensions; +using NadekoBot.Modules.Gambling; + +namespace NadekoBot.Services +{ + public static class CurrencyHandler + { + public static async Task RemoveCurrencyAsync(IGuildUser author, string reason, long amount, bool sendMessage) + { + if (amount < 0) + throw new ArgumentNullException(nameof(amount)); + + + using (var uow = DbHandler.UnitOfWork()) + { + var success = uow.Currency.TryUpdateState(author.Id, amount); + if (!success) + return false; + await uow.CompleteAsync(); + } + + if (sendMessage) + try { await author.SendMessageAsync($"`You received:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } + + return true; + } + + public static async Task AddCurrencyAsync(IGuildUser author, string reason, long amount, bool sendMessage) + { + if (amount < 0) + throw new ArgumentNullException(nameof(amount)); + + + using (var uow = DbHandler.UnitOfWork()) + { + uow.Currency.TryUpdateState(author.Id, amount); + await uow.CompleteAsync(); + } + + if (sendMessage) + await author.SendMessageAsync($"`You received:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); + } + } +} diff --git a/src/NadekoBot/Services/Database/Models/Currency.cs b/src/NadekoBot/Services/Database/Models/Currency.cs new file mode 100644 index 00000000..5bc8b8d5 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Currency.cs @@ -0,0 +1,14 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class Currency : DbEntity + { + public ulong UserId { get; set; } + public long Amount { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/ICurrencyRepository.cs b/src/NadekoBot/Services/Database/Repositories/ICurrencyRepository.cs new file mode 100644 index 00000000..c6e545df --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/ICurrencyRepository.cs @@ -0,0 +1,17 @@ +ο»Ώusing NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface ICurrencyRepository : IRepository + { + Currency GetOrCreate(ulong userId); + long GetUserCurrency(ulong userId); + bool TryUpdateState(ulong userId, long change); + IEnumerable GetTopRichest(int count); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/CurrencyRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/CurrencyRepository.cs new file mode 100644 index 00000000..f9bcdbe7 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/CurrencyRepository.cs @@ -0,0 +1,60 @@ +ο»Ώusing NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class CurrencyRepository : Repository, ICurrencyRepository + { + public CurrencyRepository(DbContext context) : base(context) + { + } + + public Currency GetOrCreate(ulong userId) + { + var cur = _set.FirstOrDefault(c => c.UserId == userId); + + if (cur == null) + { + _set.Add(cur = new Currency() + { + UserId = userId, + Amount = 0 + }); + _context.SaveChanges(); + } + return cur; + } + + public IEnumerable GetTopRichest(int count) => + _set.OrderByDescending(c => c.Amount).Take(count).ToList(); + + public long GetUserCurrency(ulong userId) => + GetOrCreate(userId).Amount; + + public bool TryUpdateState(ulong userId, long change) + { + var cur = GetOrCreate(userId); + + if (change == 0) + return true; + + if (change > 0) + { + cur.Amount += change; + return true; + } + //change is negative + if (cur.Amount + change >= 0) + { + cur.Amount += change; + return true; + } + return false; + } + } +} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 11dca26f..f8e42e64 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -36,6 +36,9 @@ namespace NadekoBot.Services.Database private IRepeaterRepository _repeaters; public IRepeaterRepository Repeaters => _repeaters ?? (_repeaters = new RepeaterRepository(_context)); + private ICurrencyRepository _currency; + public ICurrencyRepository Currency => _currency ?? (_currency = new CurrencyRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context;