Images service almost done. Slots images moved to /data/images/slots currency_images renamed to currency and moved to data/images/

This commit is contained in:
Kwoth committed 2017-02-04 09:34:51 +01:00
1 parent 5fba2de3a6
commit d39e544567
29 files changed
+228 -126

No files matched your search

@@ -0,0 +1,82 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.DataStructures
{
public static class DisposableReadOnlyListExtensions
{
public static IDisposableReadOnlyList<T> AsDisposable<T>(this IReadOnlyList<T> arr) where T : IDisposable
=> new DisposableReadOnlyList<T>(arr);
public static IDisposableReadOnlyList<KeyValuePair<TKey, TValue>> AsDisposable<TKey, TValue>(this IReadOnlyList<KeyValuePair<TKey, TValue>> arr) where TValue : IDisposable
=> new DisposableReadOnlyList<TKey, TValue>(arr);
}
public interface IDisposableReadOnlyList<T> : IReadOnlyList<T>, IDisposable
{
}
public class DisposableReadOnlyList<T> : IDisposableReadOnlyList<T>
where T : IDisposable
{
private readonly IReadOnlyList<T> _arr;
public int Count => _arr.Count;
public T this[int index] => _arr[index];
public DisposableReadOnlyList(IReadOnlyList<T> arr)
{
this._arr = arr;
}
public IEnumerator<T> GetEnumerator()
=> _arr.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> _arr.GetEnumerator();
public void Dispose()
{
foreach (var item in _arr)
{
item.Dispose();
}
}
}
public class DisposableReadOnlyList<T, U> : IDisposableReadOnlyList<KeyValuePair<T, U>>
where U : IDisposable
{
private readonly IReadOnlyList<KeyValuePair<T, U>> _arr;
public int Count => _arr.Count;
KeyValuePair<T, U> IReadOnlyList<KeyValuePair<T, U>>.this[int index] => _arr[index];
public DisposableReadOnlyList(IReadOnlyList<KeyValuePair<T, U>> arr)
{
this._arr = arr;
}
public IEnumerator<KeyValuePair<T, U>> GetEnumerator() =>
_arr.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
_arr.GetEnumerator();
public void Dispose()
{
foreach (var item in _arr)
{
item.Value.Dispose();
}
}
}
}
@@ -173,10 +173,8 @@ namespace NadekoBot.Modules.Administration
[OwnerOnly]
public async Task ReloadImages()
{
var sw = Stopwatch.StartNew();
await NadekoBot.Images.Reload().ConfigureAwait(false);
sw.Stop();
await Context.Channel.SendConfirmAsync("Images Reloaded").ConfigureAwait(false);
var time = await NadekoBot.Images.Reload().ConfigureAwait(false);
await Context.Channel.SendConfirmAsync($"Images loaded after {time.TotalSeconds:F3}s!").ConfigureAwait(false);
}
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)
@@ -34,15 +34,11 @@ namespace NadekoBot.Modules.Gambling
var num2 = gen % 10;
var imageStream = await Task.Run(() =>
{
try
{
var ms = new MemoryStream();
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
ms.Position = 0;
return ms;
}
catch { return new MemoryStream(); }
});
var ms = new MemoryStream();
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
ms.Position = 0;
return ms;
}).ConfigureAwait(false);
await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false);
}
@@ -82,7 +78,7 @@ namespace NadekoBot.Modules.Gambling
await InternallDndRoll(arg, false).ConfigureAwait(false);
}
private async Task InternalRoll( int num, bool ordered)
private async Task InternalRoll(int num, bool ordered)
{
if (num < 1 || num > 30)
{
@@ -209,20 +205,24 @@ namespace NadekoBot.Modules.Gambling
private Image GetDice(int num)
{
const string pathToImage = "data/images/dice";
if (num != 10)
if (num < 0 || num > 10)
throw new ArgumentOutOfRangeException(nameof(num));
if (num == 10)
{
using (var stream = File.OpenRead(Path.Combine(pathToImage, $"{num}.png")))
return new Image(stream);
var images = NadekoBot.Images.Dice;
using (var imgOneStream = images[1].Value.ToStream())
using (var imgZeroStream = images[0].Value.ToStream())
{
Image imgOne = new Image(imgOneStream);
Image imgZero = new Image(imgZeroStream);
return new[] { imgOne, imgZero }.Merge();
}
}
using (var one = File.OpenRead(Path.Combine(pathToImage, "1.png")))
using (var zero = File.OpenRead(Path.Combine(pathToImage, "0.png")))
using (var die = NadekoBot.Images.Dice[num].Value.ToStream())
{
Image imgOne = new Image(one);
Image imgZero = new Image(zero);
return new[] { imgOne, imgZero }.Merge();
return new Image(die);
}
}
}
@@ -5,6 +5,7 @@ using NadekoBot.Attributes;
using NadekoBot.Extensions;
using NadekoBot.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Image = ImageSharp.Image;
@@ -32,9 +33,19 @@ namespace NadekoBot.Modules.Gambling
if (count == 1)
{
if (rng.Next(0, 2) == 1)
await Context.Channel.SendFileAsync(_images.Heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
{
using (var heads = _images.Heads.ToStream())
{
await Context.Channel.SendFileAsync(heads, "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
}
}
else
await Context.Channel.SendFileAsync(_images.Tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
{
using (var tails = _images.Tails.ToStream())
{
await Context.Channel.SendFileAsync(tails, "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
}
}
return;
}
if (count > 10 || count < 1)
@@ -43,13 +54,17 @@ namespace NadekoBot.Modules.Gambling
return;
}
var imgs = new Image[count];
for (var i = 0; i < count; i++)
using (var heads = _images.Heads.ToStream())
using(var tails = _images.Tails.ToStream())
{
imgs[i] = rng.Next(0, 10) < 5 ?
new Image(_images.Heads) :
new Image(_images.Tails);
for (var i = 0; i < count; i++)
{
imgs[i] = rng.Next(0, 10) < 5 ?
new Image(heads) :
new Image(tails);
}
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
}
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
}
[NadekoCommand, Usage, Description, Aliases]
@@ -74,9 +89,10 @@ namespace NadekoBot.Modules.Gambling
//heads = true
//tails = false
//todo this seems stinky, no time to look at it right now
var isHeads = guessStr == "HEADS" || guessStr == "H";
bool result = false;
Stream imageToSend;
IEnumerable<byte> imageToSend;
if (rng.Next(0, 2) == 1)
{
imageToSend = _images.Heads;
@@ -98,8 +114,10 @@ namespace NadekoBot.Modules.Gambling
{
str = $"{Context.User.Mention}`Better luck next time.`";
}
await Context.Channel.SendFileAsync(imageToSend, "result.png", str).ConfigureAwait(false);
using (var toSend = imageToSend.ToStream())
{
await Context.Channel.SendFileAsync(toSend, "result.png", str).ConfigureAwait(false);
}
}
}
}
@@ -21,52 +21,19 @@ namespace NadekoBot.Modules.Gambling
private static int totalBet = 0;
private static int totalPaidOut = 0;
private const string backgroundPath = "data/slots/background.png";
private static readonly byte[] backgroundBuffer;
private static readonly byte[][] numbersBuffer = new byte[10][];
private static readonly byte[][] emojiBuffer;
const int alphaCutOut = byte.MaxValue / 3;
static Slots()
{
backgroundBuffer = File.ReadAllBytes(backgroundPath);
for (int i = 0; i < 10; i++)
{
numbersBuffer[i] = File.ReadAllBytes("data/slots/" + i + ".png");
}
int throwaway;
var emojiFiles = Directory.GetFiles("data/slots/emojis/", "*.png")
.Where(f => int.TryParse(Path.GetFileNameWithoutExtension(f), out throwaway))
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
.ToArray();
emojiBuffer = new byte[emojiFiles.Length][];
for (int i = 0; i < emojiFiles.Length; i++)
{
emojiBuffer[i] = File.ReadAllBytes(emojiFiles[i]);
}
}
private static MemoryStream InternalGetStream(string path)
{
var ms = new MemoryStream();
using (var fs = File.Open(path, FileMode.Open))
{
fs.CopyTo(ms);
fs.Flush();
}
ms.Position = 0;
return ms;
}
//here is a payout chart
//https://lh6.googleusercontent.com/-i1hjAJy_kN4/UswKxmhrbPI/AAAAAAAAB1U/82wq_4ZZc-Y/DE6B0895-6FC1-48BE-AC4F-14D1B91AB75B.jpg
//thanks to judge for helping me with this
private readonly IImagesService _images;
public Slots()
{
this._images = NadekoBot.Images;
}
public class SlotMachine
{
public const int MaxValue = 5;
@@ -154,7 +121,7 @@ namespace NadekoBot.Modules.Gambling
var sb = new StringBuilder();
const int bet = 1;
int payout = 0;
foreach (var key in dict.Keys.OrderByDescending(x=>x))
foreach (var key in dict.Keys.OrderByDescending(x => x))
{
sb.AppendLine($"x{key} occured {dict[key]} times. {dict[key] * 1.0f / tests * 100}%");
payout += key * dict[key];
@@ -164,6 +131,7 @@ namespace NadekoBot.Modules.Gambling
}
static HashSet<ulong> runningUsers = new HashSet<ulong>();
[NadekoCommand, Usage, Description, Aliases]
public async Task Slot(int amount = 0)
{
@@ -189,7 +157,7 @@ namespace NadekoBot.Modules.Gambling
return;
}
Interlocked.Add(ref totalBet, amount);
using (var bgFileStream = new MemoryStream(backgroundBuffer))
using (var bgFileStream = NadekoBot.Images.SlotBackground.ToStream())
{
var bgImage = new ImageSharp.Image(bgFileStream);
@@ -199,7 +167,7 @@ namespace NadekoBot.Modules.Gambling
{
for (int i = 0; i < 3; i++)
{
using (var file = new MemoryStream(emojiBuffer[numbers[i]]))
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
{
var randomImage = new ImageSharp.Image(file);
using (var toAdd = randomImage.Lock())
@@ -226,7 +194,7 @@ namespace NadekoBot.Modules.Gambling
do
{
var digit = printWon % 10;
using (var fs = new MemoryStream(numbersBuffer[digit]))
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
{
var img = new ImageSharp.Image(fs);
using (var pixels = img.Lock())
@@ -251,7 +219,7 @@ namespace NadekoBot.Modules.Gambling
do
{
var digit = printAmount % 10;
using (var fs = new MemoryStream(numbersBuffer[digit]))
using (var fs = _images.SlotNumbers[digit].ToStream())
{
var img = new ImageSharp.Image(fs);
using (var pixels = img.Lock())
@@ -301,4 +269,4 @@ namespace NadekoBot.Modules.Gambling
}
}
}
}
}
@@ -10,6 +10,7 @@ using NLog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -97,13 +98,16 @@ namespace NadekoBot.Modules.Games
firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!";
}
var file = GetRandomCurrencyImage();
var sent = await channel.SendFileAsync(
file.Item2,
file.Item1,
$"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
.ConfigureAwait(false);
using (var fileStream = file.Value.ToStream())
{
var sent = await channel.SendFileAsync(
fileStream,
file.Key,
$"❗ {firstPart} Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
.ConfigureAwait(false);
msgs[0] = sent;
msgs[0] = sent;
}
plantedFlowers.AddOrUpdate(channel.Id, msgs.ToList(), (id, old) => { old.AddRange(msgs); return old; });
}
@@ -167,18 +171,15 @@ namespace NadekoBot.Modules.Games
return;
}
var file = GetRandomCurrencyImage();
IUserMessage msg;
var imgData = GetRandomCurrencyImage();
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
if (file == null)
IUserMessage msg;
using (var toSend = imgData.Value.ToStream())
{
msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
}
else
{
msg = await Context.Channel.SendFileAsync(file.Item2, file.Item1, msgToSend).ConfigureAwait(false);
msg = await Context.Channel.SendFileAsync(toSend, imgData.Key, msgToSend).ConfigureAwait(false);
}
var msgs = new IUserMessage[amount];
@@ -228,12 +229,12 @@ namespace NadekoBot.Modules.Games
}
}
private static Tuple<string, Stream> GetRandomCurrencyImage()
private static KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
{
var rng = new NadekoRandom();
var images = NadekoBot.Images.Currency;
return images[rng.Next(0, images.Count)];
return images[rng.Next(0, images.Length)];
}
int GetRandomNumber()
+11 -6
View File
@@ -1,4 +1,5 @@
using System;
using NadekoBot.DataStructures;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
@@ -10,12 +11,16 @@ namespace NadekoBot.Services
{
public interface IImagesService
{
Stream Heads { get; }
Stream Tails { get; }
ImmutableArray<byte> Heads { get; }
ImmutableArray<byte> Tails { get; }
IImmutableList<Tuple<string, Stream>> Currency { get; }
IImmutableList<Tuple<string, Stream>> Dice { get; }
ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; }
ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; }
Task Reload();
ImmutableArray<byte> SlotBackground { get; }
ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; }
ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; }
Task<TimeSpan> Reload();
}
}
+49 -22
View File
@@ -1,4 +1,5 @@
using NLog;
using NadekoBot.DataStructures;
using NLog;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -15,27 +16,30 @@ namespace NadekoBot.Services.Impl
{
private readonly Logger _log;
private const string headsPath = "data/images/coins/heads.png";
private const string tailsPath = "data/images/coins/tails.png";
private const string basePath = "data/images/";
private const string currencyImagesPath = "data/currency_images";
private const string diceImagesPath = "data/images/dice";
private const string headsPath = basePath + "coins/heads.png";
private const string tailsPath = basePath + "coins/tails.png";
private byte[] heads;
public Stream Heads => new MemoryStream(heads, false);
private const string currencyImagesPath = basePath + "currency";
private const string diceImagesPath = basePath + "dice";
private const string slotBackgroundPath = basePath + "slots/background.png";
private const string slotNumbersPath = basePath + "slots/numbers/";
private const string slotEmojisPath = basePath + "slots/emojis/";
public ImmutableArray<byte> Heads { get; private set; }
public ImmutableArray<byte> Tails { get; private set; }
private byte[] tails;
public Stream Tails => new MemoryStream(tails, false);
//todo C#7
private IReadOnlyDictionary<string, byte[]> currency;
public IImmutableList<Tuple<string, Stream>> Currency =>
currency.Select(x => new Tuple<string, Stream>(x.Key, new MemoryStream(x.Value, false)))
.ToImmutableArray();
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Currency { get; private set; }
private IReadOnlyDictionary<string, byte[]> dice;
public IImmutableList<Tuple<string, Stream>> Dice =>
dice.Select(x => new Tuple<string, Stream>(x.Key, new MemoryStream(x.Value, false)))
.ToImmutableArray();
public ImmutableArray<KeyValuePair<string, ImmutableArray<byte>>> Dice { get; private set; }
public ImmutableArray<byte> SlotBackground { get; private set; }
public ImmutableArray<ImmutableArray<byte>> SlotNumbers { get; private set; }
public ImmutableArray<ImmutableArray<byte>> SlotEmojis { get; private set; }
private ImagesService()
{
@@ -49,18 +53,41 @@ namespace NadekoBot.Services.Impl
return srvc;
}
public Task Reload() => Task.Run(() =>
public Task<TimeSpan> Reload() => Task.Run(() =>
{
try
{
_log.Info("Loading images...");
var sw = Stopwatch.StartNew();
heads = File.ReadAllBytes(headsPath);
tails = File.ReadAllBytes(tailsPath);
Heads = File.ReadAllBytes(headsPath).ToImmutableArray();
Tails = File.ReadAllBytes(tailsPath).ToImmutableArray();
currency = Directory.GetFiles(currencyImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x));
dice = Directory.GetFiles(diceImagesPath).ToDictionary(x => Path.GetFileName(x), x => File.ReadAllBytes(x));
Currency = Directory.GetFiles(currencyImagesPath)
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(
Path.GetFileName(x),
File.ReadAllBytes(x).ToImmutableArray()))
.ToImmutableArray();
Dice = Directory.GetFiles(diceImagesPath)
.OrderBy(x => int.Parse(Path.GetFileNameWithoutExtension(x)))
.Select(x => new KeyValuePair<string, ImmutableArray<byte>>(x,
File.ReadAllBytes(x).ToImmutableArray()))
.ToImmutableArray();
SlotBackground = File.ReadAllBytes(slotBackgroundPath).ToImmutableArray();
SlotNumbers = Directory.GetFiles(slotNumbersPath)
.OrderBy(f => int.Parse(Path.GetFileNameWithoutExtension(f)))
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
.ToImmutableArray();
SlotEmojis = Directory.GetFiles(slotEmojisPath)
.Select(x => File.ReadAllBytes(x).ToImmutableArray())
.ToImmutableArray();
sw.Stop();
_log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!");
return sw.Elapsed;
}
catch (Exception ex)
{
+4 -1
View File
@@ -20,7 +20,10 @@ namespace NadekoBot.Extensions
{
private const string arrow_left = "⬅";
private const string arrow_right = "➡";
public static Stream ToStream(this IEnumerable<byte> bytes, bool canWrite = false)
=> new MemoryStream(bytes as byte[] ?? bytes.ToArray(), canWrite);
/// <summary>
/// danny kamisama
/// </summary>
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.