This repository has been archived on 2024-12-22. You can view files and clone it, but cannot push or open issues or pull requests.
elliebot/src/EllieBot/Modules/Games/NCanvas/NCanvasCommands.cs

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();
}
}
}