forked from EllieBotDevs/elliebot
Removing all the broken code and remaking it
This commit is contained in:
parent
9c94a66323
commit
b12102f735
858 changed files with 0 additions and 266344 deletions
src/EllieBot/Modules/Gambling/PlantPick
|
@ -1,114 +0,0 @@
|
|||
#nullable disable
|
||||
using EllieBot.Common.TypeReaders;
|
||||
using EllieBot.Modules.Gambling.Common;
|
||||
using EllieBot.Modules.Gambling.Services;
|
||||
|
||||
namespace EllieBot.Modules.Gambling;
|
||||
|
||||
public partial class Gambling
|
||||
{
|
||||
[Group]
|
||||
public partial class PlantPickCommands : GamblingSubmodule<PlantPickService>
|
||||
{
|
||||
private readonly ILogCommandService _logService;
|
||||
|
||||
public PlantPickCommands(ILogCommandService logService, GamblingConfigService gss)
|
||||
: base(gss)
|
||||
=> _logService = logService;
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Pick(string pass = null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric())
|
||||
return;
|
||||
|
||||
var picked = await _service.PickAsync(ctx.Guild.Id, (ITextChannel)ctx.Channel, ctx.User.Id, pass);
|
||||
|
||||
if (picked > 0)
|
||||
{
|
||||
var msg = await Response().NoReply().Confirm(strs.picked(N(picked), ctx.User)).SendAsync();
|
||||
msg.DeleteAfter(10);
|
||||
}
|
||||
|
||||
if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logService.AddDeleteIgnore(ctx.Message.Id);
|
||||
await ctx.Message.DeleteAsync();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Plant([OverrideTypeReader(typeof(BalanceTypeReader))] long amount, string pass = null)
|
||||
{
|
||||
if (amount < 1)
|
||||
return;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric())
|
||||
return;
|
||||
|
||||
if (((SocketGuild)ctx.Guild).CurrentUser.GuildPermissions.ManageMessages)
|
||||
{
|
||||
_logService.AddDeleteIgnore(ctx.Message.Id);
|
||||
await ctx.Message.DeleteAsync();
|
||||
}
|
||||
|
||||
var success = await _service.PlantAsync(ctx.Guild.Id,
|
||||
ctx.Channel,
|
||||
ctx.User.Id,
|
||||
ctx.User.ToString(),
|
||||
amount,
|
||||
pass);
|
||||
|
||||
if (!success)
|
||||
await Response().Error(strs.not_enough(CurrencySign)).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
#if GLOBAL_ELLIE
|
||||
[OwnerOnly]
|
||||
#endif
|
||||
public async Task GenCurrency()
|
||||
{
|
||||
var enabled = _service.ToggleCurrencyGeneration(ctx.Guild.Id, ctx.Channel.Id);
|
||||
if (enabled)
|
||||
await Response().Confirm(strs.curgen_enabled).SendAsync();
|
||||
else
|
||||
await Response().Confirm(strs.curgen_disabled).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.ManageMessages)]
|
||||
[OwnerOnly]
|
||||
public Task GenCurList(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return Task.CompletedTask;
|
||||
|
||||
var enabledIn = _service.GetAllGeneratingChannels();
|
||||
|
||||
return Response()
|
||||
.Paginated()
|
||||
.Items(enabledIn.ToList())
|
||||
.PageSize(9)
|
||||
.CurrentPage(page)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
if (!items.Any())
|
||||
return _sender.CreateEmbed().WithErrorColor().WithDescription("-");
|
||||
|
||||
return items.Aggregate(_sender.CreateEmbed().WithOkColor(),
|
||||
(eb, i) => eb.AddField(i.GuildId.ToString(), i.ChannelId));
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,390 +0,0 @@
|
|||
#nullable disable
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using EllieBot.Common.ModuleBehaviors;
|
||||
using EllieBot.Db.Models;
|
||||
using SixLabors.Fonts;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Drawing.Processing;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using Color = SixLabors.ImageSharp.Color;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
namespace EllieBot.Modules.Gambling.Services;
|
||||
|
||||
public class PlantPickService : IEService, IExecNoCommand
|
||||
{
|
||||
//channelId/last generation
|
||||
public ConcurrentDictionary<ulong, long> LastGenerations { get; } = new();
|
||||
private readonly DbService _db;
|
||||
private readonly IBotStrings _strings;
|
||||
private readonly IImageCache _images;
|
||||
private readonly FontProvider _fonts;
|
||||
private readonly ICurrencyService _cs;
|
||||
private readonly CommandHandler _cmdHandler;
|
||||
private readonly EllieRandom _rng;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly GamblingConfigService _gss;
|
||||
|
||||
private readonly ConcurrentHashSet<ulong> _generationChannels;
|
||||
private readonly SemaphoreSlim _pickLock = new(1, 1);
|
||||
|
||||
public PlantPickService(
|
||||
DbService db,
|
||||
IBotStrings strings,
|
||||
IImageCache images,
|
||||
FontProvider fonts,
|
||||
ICurrencyService cs,
|
||||
CommandHandler cmdHandler,
|
||||
DiscordSocketClient client,
|
||||
GamblingConfigService gss)
|
||||
{
|
||||
_db = db;
|
||||
_strings = strings;
|
||||
_images = images;
|
||||
_fonts = fonts;
|
||||
_cs = cs;
|
||||
_cmdHandler = cmdHandler;
|
||||
_rng = new();
|
||||
_client = client;
|
||||
_gss = gss;
|
||||
|
||||
using var uow = db.GetDbContext();
|
||||
var guildIds = client.Guilds.Select(x => x.Id).ToList();
|
||||
var configs = uow.Set<GuildConfig>()
|
||||
.AsQueryable()
|
||||
.Include(x => x.GenerateCurrencyChannelIds)
|
||||
.Where(x => guildIds.Contains(x.GuildId))
|
||||
.ToList();
|
||||
|
||||
_generationChannels = new(configs.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
|
||||
}
|
||||
|
||||
public Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg)
|
||||
=> PotentialFlowerGeneration(msg);
|
||||
|
||||
private string GetText(ulong gid, LocStr str)
|
||||
=> _strings.GetText(str, gid);
|
||||
|
||||
public bool ToggleCurrencyGeneration(ulong gid, ulong cid)
|
||||
{
|
||||
bool enabled;
|
||||
using var uow = _db.GetDbContext();
|
||||
var guildConfig = uow.GuildConfigsForId(gid, set => set.Include(gc => gc.GenerateCurrencyChannelIds));
|
||||
|
||||
var toAdd = new GCChannelId
|
||||
{
|
||||
ChannelId = cid
|
||||
};
|
||||
if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd))
|
||||
{
|
||||
guildConfig.GenerateCurrencyChannelIds.Add(toAdd);
|
||||
_generationChannels.Add(cid);
|
||||
enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var toDelete = guildConfig.GenerateCurrencyChannelIds.FirstOrDefault(x => x.Equals(toAdd));
|
||||
if (toDelete is not null)
|
||||
uow.Remove(toDelete);
|
||||
_generationChannels.TryRemove(cid);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
uow.SaveChanges();
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public IEnumerable<GuildConfigExtensions.GeneratingChannel> GetAllGeneratingChannels()
|
||||
{
|
||||
using var uow = _db.GetDbContext();
|
||||
var chs = uow.Set<GuildConfig>().GetGeneratingChannels();
|
||||
return chs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a random currency image stream, with an optional password sticked onto it.
|
||||
/// </summary>
|
||||
/// <param name="pass">Optional password to add to top left corner.</param>
|
||||
/// <returns>Stream of the currency image</returns>
|
||||
public async Task<(Stream, string)> GetRandomCurrencyImageAsync(string pass)
|
||||
{
|
||||
var curImg = await _images.GetCurrencyImageAsync();
|
||||
|
||||
if (curImg is null)
|
||||
return (new MemoryStream(), null);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(pass))
|
||||
{
|
||||
// determine the extension
|
||||
using var load = Image.Load(curImg);
|
||||
|
||||
var format = load.Metadata.DecodedImageFormat;
|
||||
// return the image
|
||||
return (curImg.ToStream(), format?.FileExtensions.FirstOrDefault() ?? "png");
|
||||
}
|
||||
|
||||
// get the image stream and extension
|
||||
return AddPassword(curImg, pass);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a password to the image.
|
||||
/// </summary>
|
||||
/// <param name="curImg">Image to add password to.</param>
|
||||
/// <param name="pass">Password to add to top left corner.</param>
|
||||
/// <returns>Image with the password in the top left corner.</returns>
|
||||
private (Stream, string) AddPassword(byte[] curImg, string pass)
|
||||
{
|
||||
// draw lower, it looks better
|
||||
pass = pass.TrimTo(10, true).ToLowerInvariant();
|
||||
using var img = Image.Load<Rgba32>(curImg);
|
||||
// choose font size based on the image height, so that it's visible
|
||||
var font = _fonts.NotoSans.CreateFont(img.Height / 12.0f, FontStyle.Bold);
|
||||
img.Mutate(x =>
|
||||
{
|
||||
// measure the size of the text to be drawing
|
||||
var size = TextMeasurer.MeasureSize(pass,
|
||||
new TextOptions(font)
|
||||
{
|
||||
Origin = new PointF(0, 0)
|
||||
});
|
||||
|
||||
// fill the background with black, add 5 pixels on each side to make it look better
|
||||
x.FillPolygon(Color.ParseHex("00000080"),
|
||||
new PointF(0, 0),
|
||||
new PointF(size.Width + 5, 0),
|
||||
new PointF(size.Width + 5, size.Height + 10),
|
||||
new PointF(0, size.Height + 10));
|
||||
|
||||
// draw the password over the background
|
||||
x.DrawText(pass, font, Color.White, new(0, 0));
|
||||
});
|
||||
// return image as a stream for easy sending
|
||||
var format = img.Metadata.DecodedImageFormat;
|
||||
return (img.ToStream(format), format.FileExtensions.FirstOrDefault() ?? "png");
|
||||
}
|
||||
|
||||
private Task PotentialFlowerGeneration(IUserMessage imsg)
|
||||
{
|
||||
if (imsg is not SocketUserMessage msg || msg.Author.IsBot)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (imsg.Channel is not ITextChannel channel)
|
||||
return Task.CompletedTask;
|
||||
|
||||
if (!_generationChannels.Contains(channel.Id))
|
||||
return Task.CompletedTask;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = _gss.Data;
|
||||
var lastGeneration = LastGenerations.GetOrAdd(channel.Id, DateTime.MinValue.ToBinary());
|
||||
var rng = new EllieRandom();
|
||||
|
||||
if (DateTime.UtcNow - TimeSpan.FromSeconds(config.Generation.GenCooldown)
|
||||
< DateTime.FromBinary(lastGeneration)) //recently generated in this channel, don't generate again
|
||||
return;
|
||||
|
||||
var num = rng.Next(1, 101) + (config.Generation.Chance * 100);
|
||||
if (num > 100 && LastGenerations.TryUpdate(channel.Id, DateTime.UtcNow.ToBinary(), lastGeneration))
|
||||
{
|
||||
var dropAmount = config.Generation.MinAmount;
|
||||
var dropAmountMax = config.Generation.MaxAmount;
|
||||
|
||||
if (dropAmountMax > dropAmount)
|
||||
dropAmount = new EllieRandom().Next(dropAmount, dropAmountMax + 1);
|
||||
|
||||
if (dropAmount > 0)
|
||||
{
|
||||
var prefix = _cmdHandler.GetPrefix(channel.Guild.Id);
|
||||
var toSend = dropAmount == 1
|
||||
? GetText(channel.GuildId, strs.curgen_sn(config.Currency.Sign))
|
||||
+ " "
|
||||
+ GetText(channel.GuildId, strs.pick_sn(prefix))
|
||||
: GetText(channel.GuildId, strs.curgen_pl(dropAmount, config.Currency.Sign))
|
||||
+ " "
|
||||
+ GetText(channel.GuildId, strs.pick_pl(prefix));
|
||||
|
||||
var pw = config.Generation.HasPassword ? GenerateCurrencyPassword().ToUpperInvariant() : null;
|
||||
|
||||
IUserMessage sent;
|
||||
var (stream, ext) = await GetRandomCurrencyImageAsync(pw);
|
||||
|
||||
await using (stream)
|
||||
sent = await channel.SendFileAsync(stream, $"currency_image.{ext}", toSend);
|
||||
|
||||
await AddPlantToDatabase(channel.GuildId,
|
||||
channel.Id,
|
||||
_client.CurrentUser.Id,
|
||||
sent.Id,
|
||||
dropAmount,
|
||||
pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a hexadecimal string from 1000 to ffff.
|
||||
/// </summary>
|
||||
/// <returns>A hexadecimal string from 1000 to ffff</returns>
|
||||
private string GenerateCurrencyPassword()
|
||||
{
|
||||
// generate a number from 1000 to ffff
|
||||
var num = _rng.Next(4096, 65536);
|
||||
// convert it to hexadecimal
|
||||
return num.ToString("x4");
|
||||
}
|
||||
|
||||
public async Task<long> PickAsync(
|
||||
ulong gid,
|
||||
ITextChannel ch,
|
||||
ulong uid,
|
||||
string pass)
|
||||
{
|
||||
await _pickLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
long amount;
|
||||
ulong[] ids;
|
||||
await using (var uow = _db.GetDbContext())
|
||||
{
|
||||
// this method will sum all plants with that password,
|
||||
// remove them, and get messageids of the removed plants
|
||||
|
||||
pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant();
|
||||
// gets all plants in this channel with the same password
|
||||
var entries = uow.Set<PlantedCurrency>()
|
||||
.AsQueryable()
|
||||
.Where(x => x.ChannelId == ch.Id && pass == x.Password)
|
||||
.ToList();
|
||||
// sum how much currency that is, and get all of the message ids (so that i can delete them)
|
||||
amount = entries.Sum(x => x.Amount);
|
||||
ids = entries.Select(x => x.MessageId).ToArray();
|
||||
// remove them from the database
|
||||
uow.RemoveRange(entries);
|
||||
|
||||
|
||||
if (amount > 0)
|
||||
// give the picked currency to the user
|
||||
await _cs.AddAsync(uid, amount, new("currency", "collect"));
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// delete all of the plant messages which have just been picked
|
||||
_ = ch.DeleteMessagesAsync(ids);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// return the amount of currency the user picked
|
||||
return amount;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_pickLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ulong?> SendPlantMessageAsync(
|
||||
ulong gid,
|
||||
IMessageChannel ch,
|
||||
string user,
|
||||
long amount,
|
||||
string pass)
|
||||
{
|
||||
try
|
||||
{
|
||||
// get the text
|
||||
var prefix = _cmdHandler.GetPrefix(gid);
|
||||
var msgToSend = GetText(gid, strs.planted(Format.Bold(user), amount + _gss.Data.Currency.Sign));
|
||||
|
||||
if (amount > 1)
|
||||
msgToSend += " " + GetText(gid, strs.pick_pl(prefix));
|
||||
else
|
||||
msgToSend += " " + GetText(gid, strs.pick_sn(prefix));
|
||||
|
||||
//get the image
|
||||
var (stream, ext) = await GetRandomCurrencyImageAsync(pass);
|
||||
// send it
|
||||
await using (stream)
|
||||
{
|
||||
var msg = await ch.SendFileAsync(stream, $"img.{ext}", msgToSend);
|
||||
// return sent message's id (in order to be able to delete it when it's picked)
|
||||
return msg.Id;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// if sending fails, return null as message id
|
||||
Log.Warning(ex, "Sending plant message failed: {Message}", ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> PlantAsync(
|
||||
ulong gid,
|
||||
IMessageChannel ch,
|
||||
ulong uid,
|
||||
string user,
|
||||
long amount,
|
||||
string pass)
|
||||
{
|
||||
// normalize it - no more than 10 chars, uppercase
|
||||
pass = pass?.Trim().TrimTo(10, true).ToUpperInvariant();
|
||||
// has to be either null or alphanumeric
|
||||
if (!string.IsNullOrWhiteSpace(pass) && !pass.IsAlphaNumeric())
|
||||
return false;
|
||||
|
||||
// remove currency from the user who's planting
|
||||
if (await _cs.RemoveAsync(uid, amount, new("put/collect", "put")))
|
||||
{
|
||||
// try to send the message with the currency image
|
||||
var msgId = await SendPlantMessageAsync(gid, ch, user, amount, pass);
|
||||
if (msgId is null)
|
||||
{
|
||||
// if it fails it will return null, if it returns null, refund
|
||||
await _cs.AddAsync(uid, amount, new("put/collect", "refund"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// if it doesn't fail, put the plant in the database for other people to pick
|
||||
await AddPlantToDatabase(gid, ch.Id, uid, msgId.Value, amount, pass);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if user doesn't have enough currency, fail
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task AddPlantToDatabase(
|
||||
ulong gid,
|
||||
ulong cid,
|
||||
ulong uid,
|
||||
ulong mid,
|
||||
long amount,
|
||||
string pass)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
uow.Set<PlantedCurrency>()
|
||||
.Add(new()
|
||||
{
|
||||
Amount = amount,
|
||||
GuildId = gid,
|
||||
ChannelId = cid,
|
||||
Password = pass,
|
||||
UserId = uid,
|
||||
MessageId = mid
|
||||
});
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
}
|
Reference in a new issue