forked from EllieBotDevs/elliebot
305 lines
No EOL
11 KiB
C#
305 lines
No EOL
11 KiB
C#
using EllieBot.Modules.Gambling.Services;
|
|
using SixLabors.Fonts;
|
|
using SixLabors.ImageSharp;
|
|
using SixLabors.ImageSharp.Advanced;
|
|
using SixLabors.ImageSharp.Drawing.Processing;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using SixLabors.ImageSharp.Processing;
|
|
using Image = SixLabors.ImageSharp.Image;
|
|
|
|
namespace EllieBot.Modules.Games;
|
|
|
|
public partial class Games
|
|
{
|
|
public sealed class NCanvasCommands : EllieModule
|
|
{
|
|
private readonly INCanvasService _service;
|
|
private readonly IHttpClientFactory _http;
|
|
private readonly FontProvider _fonts;
|
|
private readonly GamblingConfigService _gcs;
|
|
|
|
public NCanvasCommands(
|
|
INCanvasService service,
|
|
IHttpClientFactory http,
|
|
FontProvider fonts,
|
|
GamblingConfigService gcs)
|
|
{
|
|
_service = service;
|
|
_http = http;
|
|
_fonts = fonts;
|
|
_gcs = gcs;
|
|
}
|
|
|
|
[Cmd]
|
|
public async Task NCanvas()
|
|
{
|
|
var pixels = await _service.GetCanvas();
|
|
var image = new Image<Rgba32>(_service.GetWidth(), _service.GetHeight());
|
|
|
|
Parallel.For(0,
|
|
image.Height,
|
|
y =>
|
|
{
|
|
var pixelAccessor = image.DangerousGetPixelRowMemory(y);
|
|
var row = pixelAccessor.Span;
|
|
for (int x = 0; x < image.Width; x++)
|
|
{
|
|
row[x] = new Rgba32(pixels[(y * image.Width) + x]);
|
|
}
|
|
});
|
|
|
|
await using var stream = await image.ToStreamAsync();
|
|
|
|
var hint = GetText(strs.nc_hint(prefix, _service.GetWidth(), _service.GetHeight()));
|
|
await Response()
|
|
.File(stream, "ncanvas.png")
|
|
.Embed(_sender.CreateEmbed()
|
|
.WithOkColor()
|
|
#if GLOBAL_ELLIE
|
|
.WithDescription("This is not available yet.")
|
|
#endif
|
|
.WithFooter(hint)
|
|
.WithImageUrl("attachment://ncanvas.png"))
|
|
.SendAsync();
|
|
}
|
|
|
|
[Cmd]
|
|
public Task NCzoom(int row, int col)
|
|
=> NCzoom((col * _service.GetWidth()) + row);
|
|
|
|
[Cmd]
|
|
public async Task NCzoom(kwum position)
|
|
{
|
|
var w = _service.GetWidth();
|
|
var h = _service.GetHeight();
|
|
|
|
if (position < 0 || position >= w * h)
|
|
{
|
|
await Response().Error(strs.invalid_input).SendAsync();
|
|
return;
|
|
}
|
|
|
|
using var img = await GetZoomImage(position);
|
|
await using var stream = await img.ToStreamAsync();
|
|
await ctx.Channel.SendFileAsync(stream, $"zoom_{position}.png");
|
|
}
|
|
|
|
private async Task<Image<Rgba32>> GetZoomImage(kwum position)
|
|
{
|
|
var w = _service.GetWidth();
|
|
var pixels = await _service.GetPixelGroup(position);
|
|
|
|
var origX = ((position % w) - 2) * 100;
|
|
var origY = ((position / w) - 2) * 100;
|
|
|
|
var image = new Image<Rgba32>(500, 500);
|
|
|
|
const float fontSize = 30;
|
|
|
|
var posFont = _fonts.NotoSans.CreateFont(fontSize, FontStyle.Bold);
|
|
var size = TextMeasurer.MeasureSize("wwww", new TextOptions(posFont));
|
|
var scale = 100f / size.Width;
|
|
if (scale < 1)
|
|
posFont = _fonts.NotoSans.CreateFont(fontSize * scale, FontStyle.Bold);
|
|
var outlinePen = new SolidPen(SixLabors.ImageSharp.Color.Black, 1f);
|
|
|
|
Parallel.For(0,
|
|
pixels.Length,
|
|
i =>
|
|
{
|
|
var pix = pixels[i];
|
|
var startX = pix.Position % w * 100 - origX;
|
|
var startY = pix.Position / w * 100 - origY;
|
|
|
|
var color = new Rgba32(pix.Color);
|
|
image.Mutate(x => FillRectangleExtensions.Fill(x,
|
|
new SolidBrush(color),
|
|
new RectangleF(startX, startY, 100, 100)));
|
|
|
|
image.Mutate(x =>
|
|
{
|
|
x.DrawText(new RichTextOptions(posFont)
|
|
{
|
|
HorizontalAlignment = HorizontalAlignment.Center,
|
|
VerticalAlignment = VerticalAlignment.Center,
|
|
Origin = new(startX + 50, startY + 50)
|
|
},
|
|
((kwum)pix.Position).ToString().PadLeft(2, '2'),
|
|
Brushes.Solid(SixLabors.ImageSharp.Color.White),
|
|
outlinePen);
|
|
});
|
|
});
|
|
|
|
// write the position on each section of the image
|
|
return image;
|
|
}
|
|
|
|
[Cmd]
|
|
public async Task NcSetPixel(kwum position, string colorHex, [Leftover] string text = "")
|
|
{
|
|
if (position < 0 || position >= _service.GetWidth() * _service.GetHeight())
|
|
{
|
|
await Response().Error(strs.invalid_input).SendAsync();
|
|
return;
|
|
}
|
|
|
|
if (colorHex.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
|
colorHex = colorHex[2..];
|
|
|
|
if (!Rgba32.TryParseHex(colorHex, out var clr))
|
|
{
|
|
await Response().Error(strs.invalid_color).SendAsync();
|
|
return;
|
|
}
|
|
|
|
var pixel = await _service.GetPixel(position);
|
|
if (pixel is null)
|
|
{
|
|
await Response().Error(strs.nc_pixel_not_found).SendAsync();
|
|
return;
|
|
}
|
|
|
|
var prompt = GetText(strs.nc_pixel_set_confirm(Format.Code(position.ToString()),
|
|
Format.Bold(CurrencyHelper.N(pixel.Price,
|
|
Culture,
|
|
_gcs.Data.Currency.Sign))));
|
|
|
|
if (!await PromptUserConfirmAsync(_sender.CreateEmbed()
|
|
.WithPendingColor()
|
|
.WithDescription(prompt)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var result = await _service.SetPixel(position, clr.PackedValue, text, ctx.User.Id, pixel.Price);
|
|
|
|
if (result == SetPixelResult.NotEnoughMoney)
|
|
{
|
|
await Response().Error(strs.not_enough(_gcs.Data.Currency.Sign)).SendAsync();
|
|
return;
|
|
}
|
|
else if (result == SetPixelResult.InsufficientPayment)
|
|
{
|
|
await Response().Error(strs.nc_insuff_payment).SendAsync();
|
|
return;
|
|
}
|
|
else if (result == SetPixelResult.InvalidInput)
|
|
{
|
|
await Response().Error(strs.invalid_input).SendAsync();
|
|
return;
|
|
}
|
|
|
|
using var img = await GetZoomImage(position);
|
|
await using var stream = await img.ToStreamAsync();
|
|
|
|
await Response()
|
|
.Embed(_sender.CreateEmbed()
|
|
.WithOkColor()
|
|
.WithDescription(GetText(strs.nc_pixel_set(Format.Code(position.ToString()))))
|
|
.WithImageUrl($"attachment://zoom_{position}.png"))
|
|
.File(stream, $"zoom_{position}.png")
|
|
.SendAsync();
|
|
}
|
|
|
|
[Cmd]
|
|
public async Task NcPixel(int x, int y)
|
|
=> await NcPixel((y * _service.GetWidth()) + x);
|
|
|
|
[Cmd]
|
|
public async Task NcPixel(kwum position)
|
|
{
|
|
if (position < 0 || position >= _service.GetWidth() * _service.GetHeight())
|
|
{
|
|
await Response().Error(strs.invalid_input).SendAsync();
|
|
return;
|
|
}
|
|
|
|
var pixel = await _service.GetPixel(position);
|
|
if (pixel is null)
|
|
{
|
|
await Response().Error(strs.nc_pixel_not_found).SendAsync();
|
|
return;
|
|
}
|
|
|
|
var image = new Image<Rgba32>(100, 100);
|
|
image.Mutate(x
|
|
=> x.Fill(new SolidBrush(new Rgba32(pixel.Color)),
|
|
new RectangleF(0, 0, 100, 100)));
|
|
|
|
await using var stream = await image.ToStreamAsync();
|
|
|
|
var pos = new kwum(pixel.Position);
|
|
await Response()
|
|
.File(stream, $"{pixel.Position}.png")
|
|
.Embed(_sender.CreateEmbed()
|
|
.WithOkColor()
|
|
.WithDescription(string.IsNullOrWhiteSpace(pixel.Text) ? string.Empty : pixel.Text)
|
|
.WithTitle(GetText(strs.nc_pixel(pos)))
|
|
.AddField(GetText(strs.nc_position),
|
|
$"{pixel.Position % _service.GetWidth()} {pixel.Position / _service.GetWidth()}",
|
|
true)
|
|
.AddField(GetText(strs.price), pixel.Price.ToString(), true)
|
|
.AddField(GetText(strs.color), "#" + new Rgba32(pixel.Color).ToHex())
|
|
.WithImageUrl($"attachment://{pixel.Position}.png"))
|
|
.SendAsync();
|
|
}
|
|
|
|
[Cmd]
|
|
[OwnerOnly]
|
|
public async Task NcSetImg()
|
|
{
|
|
var attach = ctx.Message.Attachments.FirstOrDefault();
|
|
if (attach is null)
|
|
{
|
|
await Response().Error(strs.no_attach_found).SendAsync();
|
|
return;
|
|
}
|
|
|
|
var w = _service.GetWidth();
|
|
var h = _service.GetHeight();
|
|
if (attach.Width != w || attach.Height != h)
|
|
{
|
|
await Response().Error(strs.invalid_img_size(w, h)).SendAsync();
|
|
return;
|
|
}
|
|
|
|
if (!await PromptUserConfirmAsync(_sender.CreateEmbed()
|
|
.WithDescription(
|
|
"This will reset the canvas to the specified image. All prices, text and colors will be reset.\n\n"
|
|
+ "Are you sure you want to continue?")))
|
|
return;
|
|
|
|
using var http = _http.CreateClient();
|
|
await using var stream = await http.GetStreamAsync(attach.Url);
|
|
using var img = await Image.LoadAsync<Rgba32>(stream);
|
|
|
|
var pixels = new uint[_service.GetWidth() * _service.GetHeight()];
|
|
|
|
Parallel.For(0,
|
|
_service.GetWidth() * _service.GetHeight(),
|
|
i => pixels[i] = img[i % _service.GetWidth(), i / _service.GetWidth()].PackedValue);
|
|
|
|
// for (var y = 0; y < _service.GetHeight(); y++)
|
|
// for (var x = 0; x < _service.GetWidth(); x++)
|
|
// pixels[(y * _service.GetWidth()) + x] = img[x, y].PackedValue;
|
|
|
|
await _service.SetImage(pixels);
|
|
await ctx.OkAsync();
|
|
}
|
|
|
|
[Cmd]
|
|
[OwnerOnly]
|
|
public async Task NcReset()
|
|
{
|
|
await _service.ResetAsync();
|
|
|
|
if (!await PromptUserConfirmAsync(_sender.CreateEmbed()
|
|
.WithDescription(
|
|
"This will delete all pixels and reset the canvas.\n\n"
|
|
+ "Are you sure you want to continue?")))
|
|
return;
|
|
|
|
await ctx.OkAsync();
|
|
}
|
|
}
|
|
} |