mirror of
https://github.com/barelyprofessional/KfChatDotNet.git
synced 2026-05-15 02:22:43 -04:00
Compare commits
50 Commits
7981f57a34
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d9ba821b88 | |||
| e064c37477 | |||
| 95608dcb12 | |||
| 66d66c8640 | |||
| 277207215a | |||
| b346a3b303 | |||
| b170065ca3 | |||
| 520413c3da | |||
| aa25b06ebe | |||
| 9c5e364859 | |||
| 1d197ca495 | |||
| 00462f5a8b | |||
| d157d0a0a0 | |||
| 2ad5c46835 | |||
| f6581ad1d4 | |||
| f81783019f | |||
| 9fd1124522 | |||
| 1ee91e3f6c | |||
| 1cb0ff21e4 | |||
| 32bef9f8e0 | |||
| a4b740480f | |||
| ec960d4cfe | |||
| f821a96f70 | |||
| 7eb24e7517 | |||
| 97e7e5bf17 | |||
| 02f9ac7551 | |||
| ca322bde4d | |||
| 8d06b75a57 | |||
| 94e7017f29 | |||
| 4438175d80 | |||
| e6e62388b9 | |||
| d71819819d | |||
| 7df7e7dadf | |||
| 07169f0837 | |||
| 5e2dc25c77 | |||
| 45cecb5e10 | |||
| 4d1f61bfdc | |||
| 287e453b9e | |||
| f231845320 | |||
| 0b2ae9d271 | |||
| cd3e8f6147 | |||
| 6b5e7d621b | |||
| fc6b0e2918 | |||
| 79286662ce | |||
| cf62274b4b | |||
| 972e880aa9 | |||
| f5f0ba6323 | |||
| ab94098dd2 | |||
| c79105bb44 | |||
| 000c87266e |
@@ -14,6 +14,8 @@ public class ApplicationDbContext : DbContext
|
|||||||
{
|
{
|
||||||
//modelBuilder.Entity<KasinoShopProfileDbModel>()
|
//modelBuilder.Entity<KasinoShopProfileDbModel>()
|
||||||
// .OwnsOne(p => p.StateData, b => b.ToJson());
|
// .OwnsOne(p => p.StateData, b => b.ToJson());
|
||||||
|
modelBuilder.Entity<ImageDbModel>().
|
||||||
|
OwnsOne(p => p.Metadata, b => b.ToJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<UserDbModel> Users { get; set; }
|
public DbSet<UserDbModel> Users { get; set; }
|
||||||
|
|||||||
@@ -658,6 +658,33 @@ public class ChatBot
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exposes the private task used to delete messages based on a TimeSpan in case you want to use it on-demand
|
||||||
|
/// e.g. for cleaning up a gambling message only after the game has finished
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messageUuid">The message you want to delete where you only have a message UUID
|
||||||
|
/// NOTE: The bot doesn't check against its sent message tracker, so you can use this with messages
|
||||||
|
/// the bot was not responsible for sending or were lost due to a restart.</param>
|
||||||
|
/// <param name="deleteAfter">When you want it deleted</param>
|
||||||
|
public void ScheduleMessageAutoDelete(string messageUuid, TimeSpan deleteAfter)
|
||||||
|
{
|
||||||
|
_scheduledDeletions.Add(new ScheduledAutoDeleteModel
|
||||||
|
{
|
||||||
|
Message = new SentMessageTrackerModel
|
||||||
|
{
|
||||||
|
ChatMessageUuid = messageUuid,
|
||||||
|
Delay = TimeSpan.Zero,
|
||||||
|
LastEdited = DateTimeOffset.UtcNow,
|
||||||
|
Message = "placeholder because I'm nigger rigging this shit big time",
|
||||||
|
Reference = Guid.NewGuid().ToString(),
|
||||||
|
SentAt = DateTimeOffset.UtcNow,
|
||||||
|
Status = SentMessageTrackerStatus.ResponseReceived,
|
||||||
|
Type = SentMessageType.ChatMessage
|
||||||
|
},
|
||||||
|
DeleteAt = DateTimeOffset.UtcNow.Add(deleteAfter)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Non-async method which wraps the async method for sending a chat message
|
/// Non-async method which wraps the async method for sending a chat message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using KfChatDotNetBot.Extensions;
|
using KfChatDotNetBot.Extensions;
|
||||||
@@ -6,21 +7,18 @@ using KfChatDotNetBot.Models;
|
|||||||
using KfChatDotNetBot.Models.DbModels;
|
using KfChatDotNetBot.Models.DbModels;
|
||||||
using KfChatDotNetBot.Services;
|
using KfChatDotNetBot.Services;
|
||||||
using KfChatDotNetBot.Settings;
|
using KfChatDotNetBot.Settings;
|
||||||
using KfChatDotNetWsClient.Models.Events;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace KfChatDotNetBot.Commands;
|
namespace KfChatDotNetBot.Commands;
|
||||||
|
|
||||||
public class AddImageCommand : ICommand
|
public class AddImageCommand : ICommand
|
||||||
{
|
{
|
||||||
public List<Regex> Patterns => [
|
public List<Regex> Patterns => [
|
||||||
new Regex(@"^admin image (?<key>\w+) add (?<url>.+)$"),
|
new Regex(@"^admin (image|images) (?<key>\w+) (add|add_nigger) (?<url>\S+) (?<raw>raw) (?<tags>.+)$", RegexOptions.IgnoreCase),
|
||||||
new Regex(@"^admin images (?<key>\w+) add (?<url>.+)$"),
|
new Regex(@"^admin (image|images) (?<key>\w+) (add|add_nigger) (?<url>\S+) (?<tags>.+)$", RegexOptions.IgnoreCase),
|
||||||
new Regex(@"^admin image (?<key>\w+) add_nigger (?<url>.+)$"),
|
new Regex(@"^admin (image|images) (?<key>\w+) (add|add_nigger) (?<url>\S+)$", RegexOptions.IgnoreCase)
|
||||||
new Regex(@"^admin images (?<key>\w+) add_nigger (?<url>.+)$")
|
|
||||||
];
|
];
|
||||||
public string? HelpText => "Add an image to the image rotation specified";
|
public string HelpText => "Add an image to the image rotation specified";
|
||||||
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
||||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
public RateLimitOptionsModel? RateLimitOptions => null;
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
@@ -33,11 +31,14 @@ public class AddImageCommand : ICommand
|
|||||||
if (imageKeys == null) throw new InvalidOperationException($"{BuiltIn.Keys.BotImageAcceptableKeys} was null");
|
if (imageKeys == null) throw new InvalidOperationException($"{BuiltIn.Keys.BotImageAcceptableKeys} was null");
|
||||||
var key = arguments["key"].Value;
|
var key = arguments["key"].Value;
|
||||||
var url = arguments["url"].Value;
|
var url = arguments["url"].Value;
|
||||||
|
var tags = arguments.TryGetValue("tags", out var tagsArg) ? tagsArg.Value.ToLower().Split(" ").ToList() : [];
|
||||||
var niggerMode = message.Message.Contains("add_nigger");
|
var niggerMode = message.Message.Contains("add_nigger");
|
||||||
|
// TODO: Implement real and raw mode
|
||||||
|
//var _rawMode = arguments.ContainsKey("raw");
|
||||||
if (!imageKeys.Contains(key))
|
if (!imageKeys.Contains(key))
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"Key you specified is not supported. Available keys are: {string.Join(' ', imageKeys)}", true);
|
$"Key you specified is not supported. Available keys are: {imageKeys.Humanize()}", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,23 +48,111 @@ public class AddImageCommand : ICommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.Images.AddAsync(new ImageDbModel { Key = key, Url = url, LastSeen = DateTimeOffset.MinValue }, ctx);
|
if (!Uri.TryCreate(url, UriKind.Absolute, out _))
|
||||||
|
{
|
||||||
|
await botInstance.SendWhisperAsync(user.KfId, $"The URL '{url}' you provided is not valid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = url;
|
||||||
|
// todo add automatic compression/re-upload and raw mode option
|
||||||
|
|
||||||
|
await db.Images.AddAsync(new ImageDbModel
|
||||||
|
{
|
||||||
|
Key = key, Url = result, LastSeen = DateTimeOffset.MinValue, TagList = tags,
|
||||||
|
Metadata = new ImageMetadataModel { AddedByUserId = user.Id, WhenAdded = DateTimeOffset.UtcNow }
|
||||||
|
}, ctx);
|
||||||
|
var count = await db.Images.Where(i => i.Key == key).CountAsync(cancellationToken: ctx);
|
||||||
await db.SaveChangesAsync(ctx);
|
await db.SaveChangesAsync(ctx);
|
||||||
//await botInstance.SendChatMessageAsync("Added image to database", true);
|
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you added the following media to the {key} carousel\n[img]{url}[/img]", true);
|
$"{user.FormatUsername()}, you added the following media to the {key} carousel which now has {count:N0} images[spoiler=\"Image\"][img]{url}[/img]", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddImageTagsCommand : ICommand
|
||||||
|
{
|
||||||
|
public List<Regex> Patterns => [
|
||||||
|
new Regex(@"^admin (image|images) tag (?<id>\d+) (?<tags>.+)$", RegexOptions.IgnoreCase),
|
||||||
|
new Regex(@"^(image|images) tag (?<id>\d+) (?<tags>.+)$", RegexOptions.IgnoreCase),
|
||||||
|
];
|
||||||
|
public string HelpText => "Add tags to an image";
|
||||||
|
public UserRight RequiredRight => UserRight.Guest;
|
||||||
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
|
public bool WhisperCanInvoke => false;
|
||||||
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
|
CancellationToken ctx)
|
||||||
|
{
|
||||||
|
await using var db = new ApplicationDbContext();
|
||||||
|
var id = Convert.ToInt32(arguments["id"].Value);
|
||||||
|
var tags = arguments["tags"].Value.ToLower()
|
||||||
|
.Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
|
var image = await db.Images.FirstOrDefaultAsync(i => i.Id == id, cancellationToken: ctx);
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
await botInstance.SendChatMessageAsync(
|
||||||
|
$"{user.FormatUsername()}, the image ID you specified does not exist", true,
|
||||||
|
autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tags.Any(tag => tag.Length > 50))
|
||||||
|
{
|
||||||
|
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, tag length limit is 50 characters",
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image.TagList = image.TagList.Concat(tags).Distinct().ToList();
|
||||||
|
if (image.TagList.Count > 50)
|
||||||
|
{
|
||||||
|
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, {id} has a shitload of tags already!",
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await db.SaveChangesAsync(ctx);
|
||||||
|
await botInstance.SendChatMessageAsync(
|
||||||
|
$"{user.FormatUsername()}, updated tags for image ID {id} with {image.TagList.Humanize()}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UntagImageCommand : ICommand
|
||||||
|
{
|
||||||
|
public List<Regex> Patterns => [
|
||||||
|
new Regex(@"^admin (image|images) untag (?<id>\d+)$", RegexOptions.IgnoreCase)
|
||||||
|
];
|
||||||
|
public string HelpText => "Remove tags from an image";
|
||||||
|
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
||||||
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
|
public bool WhisperCanInvoke => false;
|
||||||
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
|
CancellationToken ctx)
|
||||||
|
{
|
||||||
|
await using var db = new ApplicationDbContext();
|
||||||
|
var id = Convert.ToInt32(arguments["id"].Value);
|
||||||
|
var image = await db.Images.FirstOrDefaultAsync(i => i.Id == id, cancellationToken: ctx);
|
||||||
|
if (image == null)
|
||||||
|
{
|
||||||
|
await botInstance.SendChatMessageAsync(
|
||||||
|
$"{user.FormatUsername()}, the image ID you specified does not exist", true,
|
||||||
|
autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
image.TagList = [];
|
||||||
|
await db.SaveChangesAsync(ctx);
|
||||||
|
await botInstance.SendChatMessageAsync(
|
||||||
|
$"{user.FormatUsername()}, removed tags from {id}", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RemoveImageCommand : ICommand
|
public class RemoveImageCommand : ICommand
|
||||||
{
|
{
|
||||||
public List<Regex> Patterns => [
|
public List<Regex> Patterns => [
|
||||||
new Regex(@"^admin image (?<key>\w+) remove (?<url>.+)$"),
|
new Regex(@"^admin (image|images) (?<key>\w+) (remove|delete) (?<url>.+)$"),
|
||||||
new Regex(@"^admin images (?<key>\w+) remove (?<url>.+)$"),
|
|
||||||
new Regex(@"^admin image (?<key>\w+) delete (?<url>.+)$"),
|
|
||||||
new Regex(@"^admin images (?<key>\w+) delete (?<url>.+)$")
|
|
||||||
];
|
];
|
||||||
public string? HelpText => "Remove an image from the image rotation specified";
|
public string HelpText => "Remove an image from the image rotation specified";
|
||||||
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
||||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
public RateLimitOptionsModel? RateLimitOptions => null;
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
@@ -92,22 +181,26 @@ public class RemoveImageCommand : ICommand
|
|||||||
|
|
||||||
db.Images.Remove(image);
|
db.Images.Remove(image);
|
||||||
await db.SaveChangesAsync(ctx);
|
await db.SaveChangesAsync(ctx);
|
||||||
// await botInstance.SendChatMessageAsync("Removed image from database", true);
|
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you removed the following media from the {key} carousel\n[img]{url}[/img]", true);
|
$"{user.FormatUsername()}, you removed the following media from the {key} carousel[spoiler=\"Image\"][img]{url}[/img]", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ListImageCommand : ICommand
|
public class ListImageCommand : ICommand
|
||||||
{
|
{
|
||||||
public List<Regex> Patterns => [
|
public List<Regex> Patterns => [
|
||||||
new Regex(@"^admin image (?<key>\w+) list$"),
|
new Regex(@"^admin (image|images) (?<key>\w+) list$"),
|
||||||
new Regex(@"^admin images (?<key>\w+) list$")
|
new Regex(@"^(image|images) (?<key>\w+) list$"),
|
||||||
];
|
];
|
||||||
public string? HelpText => "Remove an image from the image rotation specified";
|
public string HelpText => "List images for a given carousel";
|
||||||
public UserRight RequiredRight => UserRight.TrueAndHonest;
|
public UserRight RequiredRight => UserRight.Guest;
|
||||||
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
public RateLimitOptionsModel? RateLimitOptions => null;
|
public RateLimitOptionsModel RateLimitOptions => new()
|
||||||
|
{
|
||||||
|
Flags = RateLimitFlags.None,
|
||||||
|
MaxInvocations = 2,
|
||||||
|
Window = TimeSpan.FromSeconds(15)
|
||||||
|
};
|
||||||
public bool WhisperCanInvoke => false;
|
public bool WhisperCanInvoke => false;
|
||||||
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
@@ -120,17 +213,19 @@ public class ListImageCommand : ICommand
|
|||||||
if (!imageKeys.Contains(key))
|
if (!imageKeys.Contains(key))
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"Key you specified is not supported. Available keys are: {string.Join(' ', imageKeys)}", true);
|
$"Key you specified is not supported. Available keys are: {imageKeys.Humanize()}", true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var images = db.Images.Where(i => i.Key == key);
|
var images = db.Images.Where(i => i.Key == key);
|
||||||
if (await images.CountAsync(cancellationToken: ctx) > 20 && await Zipline.IsZiplineEnabled())
|
if (await images.CountAsync(cancellationToken: ctx) > 10 && await Zipline.IsZiplineEnabled())
|
||||||
{
|
{
|
||||||
var content = string.Empty;
|
var content = string.Empty;
|
||||||
foreach (var image in images)
|
foreach (var image in images)
|
||||||
{
|
{
|
||||||
content += image.Url + Environment.NewLine;
|
var ts = DateTimeOffset.UtcNow - image.LastSeen;
|
||||||
|
var time = $"{ts.TotalDays:N0}d{ts.Hours:N0}h{ts.Minutes:N0}m{ts.Seconds:N0}s";
|
||||||
|
content += $"{image.Url} (ID: {image.Id}) - {time} - {image.TagList.Humanize()}" + Environment.NewLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
var paste = await Zipline.Upload(content, new MediaTypeHeaderValue("text/plain"), "1d", ctx);
|
var paste = await Zipline.Upload(content, new MediaTypeHeaderValue("text/plain"), "1d", ctx);
|
||||||
@@ -144,7 +239,7 @@ public class ListImageCommand : ICommand
|
|||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
var ts = DateTimeOffset.UtcNow - image.LastSeen;
|
var ts = DateTimeOffset.UtcNow - image.LastSeen;
|
||||||
result += $"[br]{i}: {image.Url} (Last seen {ts.TotalDays:N0}d{ts.Hours:N0}h{ts.Minutes:N0}m{ts.Seconds:N0}s ago)";
|
result += $"[br]{i}: {image.Url} (ID: {image.Id}) (Last seen {ts.TotalDays:N0}d{ts.Hours:N0}h{ts.Minutes:N0}m{ts.Seconds:N0}s ago)";
|
||||||
}
|
}
|
||||||
|
|
||||||
await botInstance.SendChatMessagesAsync(result.FancySplitMessage(partSeparator: "[br]"),
|
await botInstance.SendChatMessagesAsync(result.FancySplitMessage(partSeparator: "[br]"),
|
||||||
@@ -152,16 +247,70 @@ public class ListImageCommand : ICommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ManageImageKeyCommand : ICommand
|
||||||
|
{
|
||||||
|
public List<Regex> Patterns => [
|
||||||
|
new Regex(@"^admin (imagekey|imageskey) (?<operation>add|remove|delete) (?<key>\w+)$"),
|
||||||
|
];
|
||||||
|
public string HelpText => "Add or remove an acceptable image key from the BotImageAcceptableKeys setting";
|
||||||
|
public UserRight RequiredRight => UserRight.Admin;
|
||||||
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
|
public bool WhisperCanInvoke => true;
|
||||||
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
|
CancellationToken ctx)
|
||||||
|
{
|
||||||
|
var imageKeys = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.BotImageAcceptableKeys)).JsonDeserialize<List<string>>();
|
||||||
|
if (imageKeys == null) throw new InvalidOperationException($"{BuiltIn.Keys.BotImageAcceptableKeys} was null");
|
||||||
|
var key = arguments["key"].Value.ToLower();
|
||||||
|
var operation = arguments["operation"].Value.ToLower();
|
||||||
|
|
||||||
|
if (operation is "add")
|
||||||
|
{
|
||||||
|
if (imageKeys.Contains(key))
|
||||||
|
{
|
||||||
|
await botInstance.ReplyToUser(message, $"Key \"{key}\" is already in the acceptable keys list", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageKeys.Add(key);
|
||||||
|
await SettingsProvider.SetValueAsync(BuiltIn.Keys.BotImageAcceptableKeys, JsonSerializer.Serialize(imageKeys));
|
||||||
|
await botInstance.ReplyToUser(message,
|
||||||
|
$"Added key \"{key}\" to acceptable image keys. Current keys: {imageKeys.Humanize()}", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operation is "remove" or "delete")
|
||||||
|
{
|
||||||
|
if (!imageKeys.Contains(key))
|
||||||
|
{
|
||||||
|
await botInstance.ReplyToUser(message,
|
||||||
|
$"Key \"{key}\" is not in the acceptable keys list. Current keys: {imageKeys.Humanize()}", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageKeys.Remove(key);
|
||||||
|
await SettingsProvider.SetValueAsync(BuiltIn.Keys.BotImageAcceptableKeys, JsonSerializer.Serialize(imageKeys));
|
||||||
|
await botInstance.ReplyToUser(message,
|
||||||
|
$"Removed key \"{key}\" from acceptable image keys. Current keys: {imageKeys.Humanize()}", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await botInstance.ReplyToUser(message, $"Operation '{operation}' not supported", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[AllowAdditionalMatches]
|
[AllowAdditionalMatches]
|
||||||
public class GetRandomImage : ICommand
|
public class GetRandomImage : ICommand
|
||||||
{
|
{
|
||||||
public List<Regex> Patterns => [
|
public List<Regex> Patterns => [
|
||||||
new Regex(@"^(?<key>\w+)")
|
new Regex(@"^(?<key>\w+)$"),
|
||||||
|
new Regex(@"^(?<key>\w+) (?<search>.+)"),
|
||||||
|
new Regex("^untagged$", RegexOptions.IgnoreCase),
|
||||||
|
new Regex("i (?<search>.+)")
|
||||||
];
|
];
|
||||||
public string? HelpText => "Get a random image";
|
public string HelpText => "Get a random image";
|
||||||
public UserRight RequiredRight => UserRight.Loser;
|
public UserRight RequiredRight => UserRight.Loser;
|
||||||
public TimeSpan Timeout => TimeSpan.FromMinutes(10);
|
public TimeSpan Timeout => TimeSpan.FromMinutes(10);
|
||||||
public RateLimitOptionsModel? RateLimitOptions => new()
|
public RateLimitOptionsModel RateLimitOptions => new()
|
||||||
{
|
{
|
||||||
Window = TimeSpan.FromSeconds(30),
|
Window = TimeSpan.FromSeconds(30),
|
||||||
MaxInvocations = 7,
|
MaxInvocations = 7,
|
||||||
@@ -172,8 +321,16 @@ public class GetRandomImage : ICommand
|
|||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
{
|
{
|
||||||
await using var db = new ApplicationDbContext();
|
await using var db = new ApplicationDbContext();
|
||||||
var key = arguments["key"].Value.ToLower();
|
var untagged = message.MessageRawHtmlDecoded.EndsWith("untagged", StringComparison.CurrentCultureIgnoreCase);
|
||||||
var images = db.Images.Where(i => i.Key == key);
|
var keyKnown = arguments.TryGetValue("key", out var keyGroup);
|
||||||
|
var key = "everything";
|
||||||
|
if (keyKnown) key = keyGroup!.Value;
|
||||||
|
var searchTerm = arguments.TryGetValue("search", out var searchArg) ? searchArg.Value.ToLower().Trim() : null;
|
||||||
|
var images = db.Images.AsQueryable();
|
||||||
|
if (keyKnown)
|
||||||
|
{
|
||||||
|
images = images.Where(i => i.Key == key);
|
||||||
|
}
|
||||||
if (!await images.AnyAsync(ctx))
|
if (!await images.AnyAsync(ctx))
|
||||||
{
|
{
|
||||||
RateLimitService.RemoveMostRecentEntry(user, this);
|
RateLimitService.RemoveMostRecentEntry(user, this);
|
||||||
@@ -191,6 +348,26 @@ public class GetRandomImage : ICommand
|
|||||||
BuiltIn.Keys.BotImagePigCubeSelfDestructMax, BuiltIn.Keys.BotImageInvertedPigCubeSelfDestructDelay,
|
BuiltIn.Keys.BotImagePigCubeSelfDestructMax, BuiltIn.Keys.BotImageInvertedPigCubeSelfDestructDelay,
|
||||||
BuiltIn.Keys.BotImageChinkSelfDestruct, BuiltIn.Keys.BotImageChinkSelfDestructDelay
|
BuiltIn.Keys.BotImageChinkSelfDestruct, BuiltIn.Keys.BotImageChinkSelfDestructDelay
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
var selection = await images.ToListAsync(ctx);
|
||||||
|
// It's buried down here instead of right up the top since it needs to be a list first as SQLite doesn't have
|
||||||
|
// native support for JSON types so it won't be able to construct a query to see if it's empty using IQueryable
|
||||||
|
if (untagged)
|
||||||
|
{
|
||||||
|
selection = selection.Where(s => s.TagList.Count == 0).ToList();
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(searchTerm))
|
||||||
|
{
|
||||||
|
var searchTokens = searchTerm.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
selection = searchTokens.Aggregate(selection, (current, token) =>
|
||||||
|
current.Where(i => i.TagList.Count > 0 && i.TagList.Contains(token)).ToList());
|
||||||
|
if (selection.Count == 0)
|
||||||
|
{
|
||||||
|
RateLimitService.RemoveMostRecentEntry(user, this);
|
||||||
|
await botInstance.SendChatMessageAsync($"No image in {key} matched \"{searchTerm}\"", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
var divideBy = settings[BuiltIn.Keys.BotImageRandomSliceDivideBy].ToType<int>();
|
var divideBy = settings[BuiltIn.Keys.BotImageRandomSliceDivideBy].ToType<int>();
|
||||||
var limit = 1;
|
var limit = 1;
|
||||||
var count = await images.CountAsync(ctx);
|
var count = await images.CountAsync(ctx);
|
||||||
@@ -200,25 +377,45 @@ public class GetRandomImage : ICommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EF with SQLite can't sort on dates as it's just TEXT
|
// EF with SQLite can't sort on dates as it's just TEXT
|
||||||
var selection = (await images.ToListAsync(ctx)).OrderBy(i => i.LastSeen).Take(limit).ToList();
|
selection = selection.OrderBy(i => i.LastSeen).Take(limit).ToList();
|
||||||
// MaxValue is never returned by Next so you don't need to -1 for indexing
|
// MaxValue is never returned by Next so you don't need to -1 for indexing
|
||||||
var image = selection[new Random().Next(0, selection.Count)];
|
var image = selection[new Random().Next(0, selection.Count)];
|
||||||
image.LastSeen = DateTimeOffset.UtcNow;
|
image.LastSeen = DateTimeOffset.UtcNow;
|
||||||
db.Images.Update(image);
|
db.Images.Update(image);
|
||||||
await db.SaveChangesAsync(ctx);
|
await db.SaveChangesAsync(ctx);
|
||||||
TimeSpan? timeToDeletion = null;
|
TimeSpan? timeToDeletion = null;
|
||||||
if (key == "pigcube" && settings[BuiltIn.Keys.BotImagePigCubeSelfDestruct].ToBoolean())
|
if (image.Key == "pigcube" && settings[BuiltIn.Keys.BotImagePigCubeSelfDestruct].ToBoolean())
|
||||||
{
|
{
|
||||||
timeToDeletion = TimeSpan.FromMilliseconds(image.Url == settings[BuiltIn.Keys.BotImageInvertedCubeUrl].Value
|
timeToDeletion = TimeSpan.FromMilliseconds(image.Url == settings[BuiltIn.Keys.BotImageInvertedCubeUrl].Value
|
||||||
? settings[BuiltIn.Keys.BotImageInvertedPigCubeSelfDestructDelay].ToType<int>()
|
? settings[BuiltIn.Keys.BotImageInvertedPigCubeSelfDestructDelay].ToType<int>()
|
||||||
: new Random().Next(settings[BuiltIn.Keys.BotImagePigCubeSelfDestructMin].ToType<int>(),
|
: new Random().Next(settings[BuiltIn.Keys.BotImagePigCubeSelfDestructMin].ToType<int>(),
|
||||||
settings[BuiltIn.Keys.BotImagePigCubeSelfDestructMax].ToType<int>()));
|
settings[BuiltIn.Keys.BotImagePigCubeSelfDestructMax].ToType<int>()));
|
||||||
}
|
}
|
||||||
else if (key is "chink" or "sloppa" && settings[BuiltIn.Keys.BotImageChinkSelfDestruct].ToBoolean())
|
else if (image.Key is "chink" or "sloppa" && settings[BuiltIn.Keys.BotImageChinkSelfDestruct].ToBoolean())
|
||||||
{
|
{
|
||||||
RateLimitService.AddEntry(user, this, message.MessageRawHtmlDecoded);
|
RateLimitService.AddEntry(user, this, message.MessageRawHtmlDecoded);
|
||||||
timeToDeletion = TimeSpan.FromMilliseconds(settings[BuiltIn.Keys.BotImageChinkSelfDestructDelay].ToType<int>());
|
timeToDeletion = TimeSpan.FromMilliseconds(settings[BuiltIn.Keys.BotImageChinkSelfDestructDelay].ToType<int>());
|
||||||
}
|
}
|
||||||
await botInstance.SendChatMessageAsync($"[img]{image.Url}[/img]", true, autoDeleteAfter: timeToDeletion);
|
|
||||||
|
var addedBy = "Unknown";
|
||||||
|
var whenAdded = "Unknown";
|
||||||
|
if (image.Metadata != null)
|
||||||
|
{
|
||||||
|
var addedByUser = await db.Users.FirstOrDefaultAsync(u => u.Id == image.Metadata.AddedByUserId, cancellationToken: ctx);
|
||||||
|
addedBy = addedByUser?.KfUsername ?? $"User ID {image.Metadata.AddedByUserId} for this image didn't point to a real user?";
|
||||||
|
whenAdded = image.Metadata.WhenAdded.ToString("yyyy-MM-dd HH:mm:ss zzz");
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageMeta =
|
||||||
|
$"[size=60][spoiler=\"Image Info\"][heading=1]ID: {image.Id}; Tags: {image.TagList.Humanize()}; Carousel: {image.Key}; Added By: {addedBy}; Date Added: {whenAdded}[/heading][/spoiler][/size]";
|
||||||
|
|
||||||
|
var tagNag = string.Empty;
|
||||||
|
if (image.TagList.Count == 0)
|
||||||
|
{
|
||||||
|
tagNag = $"[br]This image has no tags. You can add some using [ditto]!images tag {image.Id} [/ditto]";
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = $"[img]{image.Url}[/img]{tagNag}[br]{imageMeta}";
|
||||||
|
await botInstance.SendChatMessageAsync(result, true, autoDeleteAfter: timeToDeletion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Humanizer;
|
||||||
|
using KfChatDotNetBot.Extensions;
|
||||||
|
using KfChatDotNetBot.Models;
|
||||||
|
using KfChatDotNetBot.Models.DbModels;
|
||||||
|
using KfChatDotNetBot.Services;
|
||||||
|
using KfChatDotNetBot.Settings;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Commands.Kasino;
|
||||||
|
|
||||||
|
[KasinoCommand]
|
||||||
|
public class GetBiggestWins : ICommand
|
||||||
|
{
|
||||||
|
public List<Regex> Patterns => [
|
||||||
|
new Regex("^kasino bigwins", RegexOptions.IgnoreCase)
|
||||||
|
];
|
||||||
|
public string? HelpText => "Big wins for the current gameday";
|
||||||
|
public UserRight RequiredRight => UserRight.Loser;
|
||||||
|
public TimeSpan Timeout => TimeSpan.FromSeconds(10);
|
||||||
|
public RateLimitOptionsModel? RateLimitOptions => null;
|
||||||
|
public bool WhisperCanInvoke => false;
|
||||||
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
|
CancellationToken ctx)
|
||||||
|
{
|
||||||
|
await using var db = new ApplicationDbContext();
|
||||||
|
var gameDay = await Money.GetKasinoDate();
|
||||||
|
var wagers = await db.Wagers.Where(x => x.TimeUnixEpochSeconds > gameDay.ToUnixTimeSeconds())
|
||||||
|
.Include(x => x.Gambler).ThenInclude(x => x.User).ToListAsync(ctx);
|
||||||
|
var biggestMultees = wagers.OrderByDescending(x => x.Multiplier).Take(10).ToList();
|
||||||
|
var biggestWins = wagers.OrderByDescending(x => x.WagerEffect).Take(10).ToList();
|
||||||
|
var multeesMsg =
|
||||||
|
$"Big multees adding up to {await biggestMultees.Sum(x => x.WagerEffect).FormatKasinoCurrencyAsync()}:";
|
||||||
|
var i = 0;
|
||||||
|
foreach (var win in biggestMultees)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
var winPlusWager = win.WagerEffect + win.WagerAmount;
|
||||||
|
multeesMsg += $"[br]{i}. {win.Gambler.User.FormatUsername()} bet {await win.WagerAmount.FormatKasinoCurrencyAsync()} on {win.Game.Humanize()} and won {await winPlusWager.FormatKasinoCurrencyAsync()} ({win.Multiplier:N2}x)";
|
||||||
|
}
|
||||||
|
var bigWinsMsg = $"Big wins adding up to {await biggestWins.Sum(x => x.WagerEffect).FormatKasinoCurrencyAsync()}:";
|
||||||
|
i = 0;
|
||||||
|
foreach (var win in biggestWins)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
var winPlusWager = win.WagerEffect + win.WagerAmount;
|
||||||
|
bigWinsMsg += $"[br]{i}. {win.Gambler.User.FormatUsername()} bet {await win.WagerAmount.FormatKasinoCurrencyAsync()} on {win.Game.Humanize()} and won {await winPlusWager.FormatKasinoCurrencyAsync()} ({win.Multiplier:N2}x)";
|
||||||
|
}
|
||||||
|
|
||||||
|
var msgs = new List<string>
|
||||||
|
{
|
||||||
|
$"Top 10 biggest wins for game day {gameDay:yyyy-MM-dd}" +
|
||||||
|
$"[spoiler=\"Big Multees\"]{multeesMsg}[/spoiler]",
|
||||||
|
$"[spoiler=\"Big Wins\"]{bigWinsMsg}[/spoiler]"
|
||||||
|
};
|
||||||
|
|
||||||
|
await botInstance.SendChatMessagesAsync(msgs, true, autoDeleteAfter: TimeSpan.FromSeconds(60));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ public class GetBalanceCommand : ICommand
|
|||||||
{
|
{
|
||||||
public List<Regex> Patterns => [
|
public List<Regex> Patterns => [
|
||||||
new Regex("^balance", RegexOptions.IgnoreCase),
|
new Regex("^balance", RegexOptions.IgnoreCase),
|
||||||
new Regex("^bal$", RegexOptions.IgnoreCase)
|
new Regex("^bal$", RegexOptions.IgnoreCase),
|
||||||
|
new Regex("^bal exact$", RegexOptions.IgnoreCase)
|
||||||
];
|
];
|
||||||
public string? HelpText => "Get your gamba balance";
|
public string? HelpText => "Get your gamba balance";
|
||||||
public UserRight RequiredRight => UserRight.Loser;
|
public UserRight RequiredRight => UserRight.Loser;
|
||||||
@@ -30,8 +31,17 @@ public class GetBalanceCommand : ICommand
|
|||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
{
|
{
|
||||||
var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx);
|
var gambler = await Money.GetGamblerEntityAsync(user.Id, ct: ctx);
|
||||||
|
if (message.MessageRawHtmlDecoded.EndsWith("exact"))
|
||||||
|
{
|
||||||
|
await botInstance.SendChatMessageAsync(
|
||||||
|
$"{user.FormatUsername()}, your balance is {gambler!.Balance}", true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, your balance is {await gambler!.Balance.FormatKasinoCurrencyAsync()}", true);
|
$"{user.FormatUsername()}, your balance is {await gambler!.Balance.FormatKasinoCurrencyAsync()}", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (botInstance.BotServices.KasinoShop != null)
|
if (botInstance.BotServices.KasinoShop != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ public class KenoCommand : ICommand
|
|||||||
private const string BlankSpaceDisplay = "⬛";
|
private const string BlankSpaceDisplay = "⬛";
|
||||||
|
|
||||||
private SentMessageTrackerModel? _kenoTable;
|
private SentMessageTrackerModel? _kenoTable;
|
||||||
|
private CancellationToken _ct;
|
||||||
|
|
||||||
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
{
|
{
|
||||||
|
_ct = ctx;
|
||||||
var settings = await SettingsProvider.GetMultipleValuesAsync([
|
var settings = await SettingsProvider.GetMultipleValuesAsync([
|
||||||
BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay, BuiltIn.Keys.KasinoKenoCleanupDelay,
|
BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay, BuiltIn.Keys.KasinoKenoCleanupDelay,
|
||||||
BuiltIn.Keys.KasinoKenoFrameDelay, BuiltIn.Keys.KasinoKenoEnabled
|
BuiltIn.Keys.KasinoKenoFrameDelay, BuiltIn.Keys.KasinoKenoEnabled
|
||||||
@@ -249,17 +251,11 @@ public class KenoCommand : ICommand
|
|||||||
displayMessage += "[br]";
|
displayMessage += "[br]";
|
||||||
}
|
}
|
||||||
|
|
||||||
_kenoTable = await botInstance.SendChatMessageAsync(displayMessage, true);
|
var size = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KasinoKenoSize)).ToType<int>();
|
||||||
var i = 0;
|
_kenoTable = await botInstance.SendChatMessageAsync($"[size={size}]" + displayMessage.GridToTable(), true);
|
||||||
while (_kenoTable.ChatMessageUuid == null)
|
var sent = await botInstance.WaitForChatMessageAsync(_kenoTable, patience: TimeSpan.FromSeconds(30), ct: _ct);
|
||||||
{
|
|
||||||
i++;
|
|
||||||
if (_kenoTable.Status is SentMessageTrackerStatus.NotSending or SentMessageTrackerStatus.Lost) return;
|
|
||||||
if (i > 60) return;
|
|
||||||
await Task.Delay(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_kenoTable.ChatMessageUuid == null)
|
if (!sent || _kenoTable.ChatMessageUuid == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"_kenoTable chat message ID never got populated. Tracker status is: {_kenoTable?.Status}");
|
throw new Exception($"_kenoTable chat message ID never got populated. Tracker status is: {_kenoTable?.Status}");
|
||||||
}
|
}
|
||||||
@@ -293,8 +289,8 @@ public class KenoCommand : ICommand
|
|||||||
}
|
}
|
||||||
displayMessage += "[br]";
|
displayMessage += "[br]";
|
||||||
}
|
}
|
||||||
await botInstance.KfClient.EditMessageAsync(_kenoTable.ChatMessageUuid, displayMessage);
|
await botInstance.KfClient.EditMessageAsync(_kenoTable.ChatMessageUuid, $"[size={size}]" + displayMessage.GridToTable());
|
||||||
await Task.Delay(frameDelay);
|
await Task.Delay(frameDelay, _ct);
|
||||||
if (displayMessage.Length <= 79 && displayMessage.Contains(BlankSpaceDisplay) &&
|
if (displayMessage.Length <= 79 && displayMessage.Contains(BlankSpaceDisplay) &&
|
||||||
(displayMessage.Contains(CasinoNumberDisplay) || displayMessage.Contains(MatchRevealDisplay) ||
|
(displayMessage.Contains(CasinoNumberDisplay) || displayMessage.Contains(MatchRevealDisplay) ||
|
||||||
frame == 9)) continue; //every board should have blank spaces and casino numbers or matches. player numbers might be hidden by matches
|
frame == 9)) continue; //every board should have blank spaces and casino numbers or matches. player numbers might be hidden by matches
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class KrashBetCommand : ICommand
|
|||||||
if (wager > gambler.Balance)
|
if (wager > gambler.Balance)
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, your balance of {gambler.Balance} is not enough to bet {wager} on krash.",
|
$"{user.FormatUsername()}, your balance of {await gambler.Balance.FormatKasinoCurrencyAsync()} is not enough to bet {wager} on krash.",
|
||||||
true, autoDeleteAfter: TimeSpan.FromSeconds(5));
|
true, autoDeleteAfter: TimeSpan.FromSeconds(5));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public class Planes : ICommand
|
|||||||
_riggedWin = true;
|
_riggedWin = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var size = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KasinoPlanesSize)).ToType<int>();
|
||||||
var planesBoard = CreatePlanesBoard(gambler,0);
|
var planesBoard = CreatePlanesBoard(gambler,0);
|
||||||
var planesBoard2 = CreatePlanesBoard(gambler);
|
var planesBoard2 = CreatePlanesBoard(gambler);
|
||||||
var planesBoard3 = CreatePlanesBoard(gambler);
|
var planesBoard3 = CreatePlanesBoard(gambler);
|
||||||
@@ -129,7 +129,7 @@ public class Planes : ICommand
|
|||||||
var fullCounter = 0;
|
var fullCounter = 0;
|
||||||
var noseUp = true;
|
var noseUp = true;
|
||||||
var planesDisplay = GetPreGameBoard(-3, planesBoard2, plane, CarrierCount, noseUp);
|
var planesDisplay = GetPreGameBoard(-3, planesBoard2, plane, CarrierCount, noseUp);
|
||||||
var msgId = await botInstance.SendChatMessageAsync(planesDisplay, true);
|
var msgId = await botInstance.SendChatMessageAsync($"[size={size}]" + planesDisplay, true);
|
||||||
var num = 0;
|
var num = 0;
|
||||||
while (msgId.ChatMessageUuid == null)
|
while (msgId.ChatMessageUuid == null)
|
||||||
{
|
{
|
||||||
@@ -153,14 +153,14 @@ public class Planes : ICommand
|
|||||||
if (fullCounter >= 3)
|
if (fullCounter >= 3)
|
||||||
{
|
{
|
||||||
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
||||||
planesDisplay += $"[br]Multi: {plane.MultiTracker}x";
|
planesDisplay += $"[/size][br]Multi: {plane.MultiTracker}x";
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
planesDisplay += BlankSpace;
|
planesDisplay += BlankSpace;
|
||||||
}
|
}
|
||||||
var winnings = plane.MultiTracker * wager;
|
var winnings = plane.MultiTracker * wager;
|
||||||
planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}";
|
planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}";
|
||||||
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay);
|
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, $"[size={size}]" + planesDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
var neutral = false;
|
var neutral = false;
|
||||||
@@ -171,7 +171,7 @@ public class Planes : ICommand
|
|||||||
{
|
{
|
||||||
counter = (fullCounter - 3) % 24;
|
counter = (fullCounter - 3) % 24;
|
||||||
planesDisplay = GetPreGameBoard(fullCounter, planesBoard2, plane, CarrierCount, noseUp);
|
planesDisplay = GetPreGameBoard(fullCounter, planesBoard2, plane, CarrierCount, noseUp);
|
||||||
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay);
|
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, $"[size={size}]" + planesDisplay);
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx);
|
await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx);
|
||||||
fullCounter++;
|
fullCounter++;
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ public class Planes : ICommand
|
|||||||
logger.Error(e);
|
logger.Error(e);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
planesDisplay += $"[br]Multi: {plane.MultiTracker}x";
|
planesDisplay += $"[/size][br]Multi: {plane.MultiTracker}x";
|
||||||
for (var i = 0; i < 10; i++)
|
for (var i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
planesDisplay += BlankSpace;
|
planesDisplay += BlankSpace;
|
||||||
@@ -248,7 +248,7 @@ public class Planes : ICommand
|
|||||||
|
|
||||||
var winnings = plane.MultiTracker * wager;
|
var winnings = plane.MultiTracker * wager;
|
||||||
planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}";
|
planesDisplay += $"Winnings: {await winnings.FormatKasinoCurrencyAsync()}";
|
||||||
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay);
|
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, $"[size={size}]" + planesDisplay);
|
||||||
if (plane.Height > 5)
|
if (plane.Height > 5)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -276,7 +276,7 @@ public class Planes : ICommand
|
|||||||
var win = plane.MultiTracker * wager;
|
var win = plane.MultiTracker * wager;
|
||||||
newBalance = await Money.NewWagerAsync(gambler.Id, wager, win, WagerGame.Planes, ct: ctx);
|
newBalance = await Money.NewWagerAsync(gambler.Id, wager, win, WagerGame.Planes, ct: ctx);
|
||||||
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
||||||
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay);
|
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, $"[size={size}]" + planesDisplay);
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]successfully landed with {await win.FormatKasinoCurrencyAsync()} from a total {plane.MultiTracker:N2}x multi![/color]. Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}",
|
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]successfully landed with {await win.FormatKasinoCurrencyAsync()} from a total {plane.MultiTracker:N2}x multi![/color]. Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
@@ -294,7 +294,7 @@ public class Planes : ICommand
|
|||||||
newBalance = await Money.NewWagerAsync(gambler.Id, wager, -wager, WagerGame.Planes, ct: ctx);
|
newBalance = await Money.NewWagerAsync(gambler.Id, wager, -wager, WagerGame.Planes, ct: ctx);
|
||||||
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
planesDisplay = GetGameBoard(fullCounter, planesBoards, plane, CarrierCount, noseUp);
|
||||||
await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx);
|
await Task.Delay(TimeSpan.FromMilliseconds(frameLength), ctx);
|
||||||
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, planesDisplay);
|
await botInstance.KfClient.EditMessageAsync(msgId.ChatMessageUuid, $"[size={size}]" + planesDisplay);
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]crashed![/color] Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}",
|
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]crashed![/color] Your balance is now: {await newBalance.FormatKasinoCurrencyAsync()}",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
@@ -368,7 +368,7 @@ public class Planes : ICommand
|
|||||||
|
|
||||||
output += "[br]";
|
output += "[br]";
|
||||||
}
|
}
|
||||||
return output;
|
return output.GridToTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetGameBoard(int fullCounter, List<int[,]> planesBoards, Plane plane, int carrierCount, bool noseUp)
|
private string GetGameBoard(int fullCounter, List<int[,]> planesBoards, Plane plane, int carrierCount, bool noseUp)
|
||||||
@@ -445,7 +445,7 @@ public class Planes : ICommand
|
|||||||
}
|
}
|
||||||
output += "[br]";
|
output += "[br]";
|
||||||
}
|
}
|
||||||
return output;
|
return output.GridToTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[,] CreatePlanesBoard(GamblerDbModel gambler, int forceTiles = -1)
|
private int[,] CreatePlanesBoard(GamblerDbModel gambler, int forceTiles = -1)
|
||||||
|
|||||||
@@ -184,8 +184,9 @@ public class PlinkoCommand : ICommand
|
|||||||
ballsNotInPlay.Add(new PlinkoBall());
|
ballsNotInPlay.Add(new PlinkoBall());
|
||||||
}
|
}
|
||||||
//game starts here
|
//game starts here
|
||||||
|
var size = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.KasinoPlinkoSize)).ToType<int>();
|
||||||
int breakCounter = 0;
|
int breakCounter = 0;
|
||||||
var plinkoMessageID = await botInstance.SendChatMessageAsync(PlinkoBoardDisplay(ballsInPlay), true, autoDeleteAfter: cleanupDelay);
|
var plinkoMessageID = await botInstance.SendChatMessageAsync($"[size={size}]" + PlinkoBoardDisplay(ballsInPlay), true, autoDeleteAfter: cleanupDelay);
|
||||||
while (plinkoMessageID.ChatMessageUuid == null && breakCounter < 1000) {
|
while (plinkoMessageID.ChatMessageUuid == null && breakCounter < 1000) {
|
||||||
await Task.Delay(100, ctx);
|
await Task.Delay(100, ctx);
|
||||||
breakCounter++;
|
breakCounter++;
|
||||||
@@ -207,7 +208,7 @@ public class PlinkoCommand : ICommand
|
|||||||
ballsInPlay.Add(ballsNotInPlay[0]);
|
ballsInPlay.Add(ballsNotInPlay[0]);
|
||||||
ballsNotInPlay.RemoveAt(0);
|
ballsNotInPlay.RemoveAt(0);
|
||||||
}
|
}
|
||||||
PlinkoMessage = PlinkoBoardDisplay(ballsInPlay) + "[br]" + lastPayoutMessage;
|
PlinkoMessage = $"[size={size}]" + PlinkoBoardDisplay(ballsInPlay) + "[/size][br]" + lastPayoutMessage;
|
||||||
await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage);
|
await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage);
|
||||||
if (ballsInPlay[0].POSITION.row == DIFFICULTY - 1) //once your ball has reached the bottom calculate the payout
|
if (ballsInPlay[0].POSITION.row == DIFFICULTY - 1) //once your ball has reached the bottom calculate the payout
|
||||||
{
|
{
|
||||||
@@ -231,7 +232,7 @@ public class PlinkoCommand : ICommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(300, ctx);
|
await Task.Delay(300, ctx);
|
||||||
PlinkoMessage = PlinkoBoardDisplay(ballsInPlay) + "[br]" + lastPayoutMessage;
|
PlinkoMessage = $"[size={size}]"+PlinkoBoardDisplay(ballsInPlay) + "[/size][br]" + lastPayoutMessage;
|
||||||
await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage);
|
await botInstance.KfClient.EditMessageAsync(plinkoMessageID.ChatMessageUuid!, PlinkoMessage);
|
||||||
await Task.Delay(300, ctx);
|
await Task.Delay(300, ctx);
|
||||||
|
|
||||||
@@ -293,7 +294,7 @@ public class PlinkoCommand : ICommand
|
|||||||
board += "[br]";
|
board += "[br]";
|
||||||
}
|
}
|
||||||
|
|
||||||
return board;
|
return board.GridToTable();
|
||||||
}
|
}
|
||||||
public class PlinkoBall
|
public class PlinkoBall
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ public class RainCommand : ICommand
|
|||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"LFG {user.FormatUsername()} is now a participant! There's now {rain.Participants.Count + 1} participant{pluralSuffix}! Type [ditto]!rain[/ditto] to participate",
|
$"LFG {user.FormatUsername()} is now a participant! There's now {rain.Participants.Count + 1} participant{pluralSuffix}! Type [ditto]!rain[/ditto] to participate",
|
||||||
true, autoDeleteAfter: cleanupDelay);
|
true, autoDeleteAfter: cleanupDelay);
|
||||||
|
await botInstance.KfClient.DeleteMessageAsync(message.MessageUuid!);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//if you're trying to start the rain
|
//if you're trying to start the rain
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using KfChatDotNetBot.Models;
|
|||||||
using KfChatDotNetBot.Models.DbModels;
|
using KfChatDotNetBot.Models.DbModels;
|
||||||
using KfChatDotNetBot.Services;
|
using KfChatDotNetBot.Services;
|
||||||
using KfChatDotNetBot.Settings;
|
using KfChatDotNetBot.Settings;
|
||||||
using KfChatDotNetWsClient.Models.Events;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NLog;
|
using NLog;
|
||||||
using SixLabors.Fonts;
|
using SixLabors.Fonts;
|
||||||
@@ -35,7 +34,7 @@ public class RouletteCommand : ICommand
|
|||||||
|
|
||||||
public string? HelpText => "!roulette <amount> <bet> - Bet types: number (0-36), red/black, odd/even, low/high, 1st12/2nd12/3rd12, col1/col2/col3";
|
public string? HelpText => "!roulette <amount> <bet> - Bet types: number (0-36), red/black, odd/even, low/high, 1st12/2nd12/3rd12, col1/col2/col3";
|
||||||
public UserRight RequiredRight => UserRight.Loser;
|
public UserRight RequiredRight => UserRight.Loser;
|
||||||
public TimeSpan Timeout => TimeSpan.FromSeconds(5);
|
public TimeSpan Timeout => TimeSpan.FromSeconds(300);
|
||||||
public RateLimitOptionsModel? RateLimitOptions => new()
|
public RateLimitOptionsModel? RateLimitOptions => new()
|
||||||
{
|
{
|
||||||
MaxInvocations = 10,
|
MaxInvocations = 10,
|
||||||
@@ -47,6 +46,7 @@ public class RouletteCommand : ICommand
|
|||||||
private IDatabase? _redisDb;
|
private IDatabase? _redisDb;
|
||||||
|
|
||||||
private ApplicationDbContext _dbContext = new();
|
private ApplicationDbContext _dbContext = new();
|
||||||
|
private CancellationToken _ct;
|
||||||
|
|
||||||
// European Roulette wheel configuration
|
// European Roulette wheel configuration
|
||||||
private static readonly HashSet<int> BlackNumbers = new()
|
private static readonly HashSet<int> BlackNumbers = new()
|
||||||
@@ -58,6 +58,7 @@ public class RouletteCommand : ICommand
|
|||||||
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
public async Task RunCommand(ChatBot botInstance, BotCommandMessageModel message, UserDbModel user, GroupCollection arguments,
|
||||||
CancellationToken ctx)
|
CancellationToken ctx)
|
||||||
{
|
{
|
||||||
|
_ct = ctx;
|
||||||
var settings = await SettingsProvider.GetMultipleValuesAsync([
|
var settings = await SettingsProvider.GetMultipleValuesAsync([
|
||||||
BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay,
|
BuiltIn.Keys.KasinoGameDisabledMessageCleanupDelay,
|
||||||
BuiltIn.Keys.KasinoRouletteEnabled,
|
BuiltIn.Keys.KasinoRouletteEnabled,
|
||||||
@@ -76,7 +77,7 @@ public class RouletteCommand : ICommand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(settings[BuiltIn.Keys.BotRedisConnectionString].Value))
|
if (!Redis.IsAvailable)
|
||||||
{
|
{
|
||||||
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, roulette is not available at this time", true,
|
await botInstance.SendChatMessageAsync($"{user.FormatUsername()}, roulette is not available at this time", true,
|
||||||
autoDeleteAfter: TimeSpan.FromSeconds(15));
|
autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
@@ -271,7 +272,7 @@ public class RouletteCommand : ICommand
|
|||||||
|
|
||||||
// Wait until message is fully sent
|
// Wait until message is fully sent
|
||||||
logger.Debug("Waiting for countdown message to be sent...");
|
logger.Debug("Waiting for countdown message to be sent...");
|
||||||
var success = await botInstance.WaitForChatMessageAsync(countdownMessage, TimeSpan.FromSeconds(30));
|
var success = await botInstance.WaitForChatMessageAsync(countdownMessage, TimeSpan.FromSeconds(30), _ct);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@@ -289,7 +290,7 @@ public class RouletteCommand : ICommand
|
|||||||
if (remaining.TotalSeconds <= 0) break;
|
if (remaining.TotalSeconds <= 0) break;
|
||||||
|
|
||||||
// Wait 1 second between updates
|
// Wait 1 second between updates
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
await Task.Delay(TimeSpan.FromSeconds(1), _ct);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -386,7 +387,7 @@ public class RouletteCommand : ICommand
|
|||||||
{
|
{
|
||||||
// Generate winning number using first gambler's seed
|
// Generate winning number using first gambler's seed
|
||||||
var firstGambler = await _dbContext.Gamblers
|
var firstGambler = await _dbContext.Gamblers
|
||||||
.FirstOrDefaultAsync(g => g.Id == round.Bets[0].GamblerId);
|
.FirstOrDefaultAsync(g => g.Id == round.Bets[0].GamblerId, cancellationToken: _ct);
|
||||||
|
|
||||||
if (firstGambler == null)
|
if (firstGambler == null)
|
||||||
{
|
{
|
||||||
@@ -398,7 +399,7 @@ public class RouletteCommand : ICommand
|
|||||||
|
|
||||||
// Generate animation
|
// Generate animation
|
||||||
logger.Info($"Generating roulette animation for round {round.RoundId}");
|
logger.Info($"Generating roulette animation for round {round.RoundId}");
|
||||||
var (animationDuration, animationBytes) = RouletteAnimationGenerator.GenerateAnimation(winningNumber);
|
var (animationDuration, animationBytes) = await RouletteAnimationGenerator.GenerateAnimation(winningNumber, _ct);
|
||||||
logger.Info($"Animation generated: {animationBytes.Length} bytes, duration: {animationDuration}s");
|
logger.Info($"Animation generated: {animationBytes.Length} bytes, duration: {animationDuration}s");
|
||||||
|
|
||||||
// Upload animation to Zipline
|
// Upload animation to Zipline
|
||||||
@@ -407,7 +408,7 @@ public class RouletteCommand : ICommand
|
|||||||
var animationUrl = await Zipline.Upload(
|
var animationUrl = await Zipline.Upload(
|
||||||
animationStream,
|
animationStream,
|
||||||
new MediaTypeHeaderValue("image/webp"),
|
new MediaTypeHeaderValue("image/webp"),
|
||||||
expiration: "1h");
|
expiration: "1h", ct: _ct);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(animationUrl))
|
if (string.IsNullOrEmpty(animationUrl))
|
||||||
{
|
{
|
||||||
@@ -432,7 +433,7 @@ public class RouletteCommand : ICommand
|
|||||||
|
|
||||||
// Wait for animation duration before revealing results
|
// Wait for animation duration before revealing results
|
||||||
logger.Info($"Waiting {animationDuration} seconds for animation to complete");
|
logger.Info($"Waiting {animationDuration} seconds for animation to complete");
|
||||||
await Task.Delay(TimeSpan.FromSeconds(animationDuration));
|
await Task.Delay(TimeSpan.FromSeconds(animationDuration), _ct);
|
||||||
|
|
||||||
// Process all bets and show results
|
// Process all bets and show results
|
||||||
await ProcessBets(botInstance, round, winningNumber);
|
await ProcessBets(botInstance, round, winningNumber);
|
||||||
@@ -459,20 +460,20 @@ public class RouletteCommand : ICommand
|
|||||||
{
|
{
|
||||||
var wager = await _dbContext.Wagers
|
var wager = await _dbContext.Wagers
|
||||||
.Include(w => w.Gambler)
|
.Include(w => w.Gambler)
|
||||||
.FirstOrDefaultAsync(w => w.Id == bet.WagerId);
|
.FirstOrDefaultAsync(w => w.Id == bet.WagerId, cancellationToken: _ct);
|
||||||
|
|
||||||
if (wager != null)
|
if (wager != null)
|
||||||
{
|
{
|
||||||
wager.IsComplete = true;
|
wager.IsComplete = true;
|
||||||
wager.WagerEffect = 0;
|
wager.WagerEffect = 0;
|
||||||
wager.Multiplier = 1;
|
wager.Multiplier = 1;
|
||||||
await _dbContext.SaveChangesAsync();
|
await _dbContext.SaveChangesAsync(_ct);
|
||||||
|
|
||||||
await Money.ModifyBalanceAsync(
|
await Money.ModifyBalanceAsync(
|
||||||
wager.Gambler.Id,
|
wager.Gambler.Id,
|
||||||
wager.WagerAmount,
|
wager.WagerAmount,
|
||||||
TransactionSourceEventType.Gambling,
|
TransactionSourceEventType.Gambling,
|
||||||
$"Roulette round {round.RoundId} cancelled due to error, wager {wager.Id} refunded");
|
$"Roulette round {round.RoundId} cancelled due to error, wager {wager.Id} refunded", ct: _ct);
|
||||||
|
|
||||||
totalRefunded += wager.WagerAmount;
|
totalRefunded += wager.WagerAmount;
|
||||||
}
|
}
|
||||||
@@ -520,7 +521,7 @@ public class RouletteCommand : ICommand
|
|||||||
{
|
{
|
||||||
var wager = await _dbContext.Wagers
|
var wager = await _dbContext.Wagers
|
||||||
.Include(w => w.Gambler)
|
.Include(w => w.Gambler)
|
||||||
.FirstOrDefaultAsync(w => w.Id == bet.WagerId);
|
.FirstOrDefaultAsync(w => w.Id == bet.WagerId, cancellationToken: _ct);
|
||||||
|
|
||||||
if (wager == null)
|
if (wager == null)
|
||||||
{
|
{
|
||||||
@@ -537,7 +538,7 @@ public class RouletteCommand : ICommand
|
|||||||
wager.WagerEffect = effect;
|
wager.WagerEffect = effect;
|
||||||
wager.Multiplier = payout / bet.Amount;
|
wager.Multiplier = payout / bet.Amount;
|
||||||
|
|
||||||
await _dbContext.SaveChangesAsync();
|
await _dbContext.SaveChangesAsync(_ct);
|
||||||
|
|
||||||
// Update balance
|
// Update balance
|
||||||
var balanceAdjustment = payout;
|
var balanceAdjustment = payout;
|
||||||
@@ -545,7 +546,7 @@ public class RouletteCommand : ICommand
|
|||||||
wager.Gambler.Id,
|
wager.Gambler.Id,
|
||||||
balanceAdjustment,
|
balanceAdjustment,
|
||||||
TransactionSourceEventType.Gambling,
|
TransactionSourceEventType.Gambling,
|
||||||
$"Roulette outcome from wager {wager.Id}");
|
$"Roulette outcome from wager {wager.Id}", ct: _ct);
|
||||||
|
|
||||||
// Track results by user
|
// Track results by user
|
||||||
if (!winnersByUser.ContainsKey(bet.Username))
|
if (!winnersByUser.ContainsKey(bet.Username))
|
||||||
@@ -923,7 +924,7 @@ public static class RouletteAnimationGenerator
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="winningNumber">The number (0-36) that the ball should land on</param>
|
/// <param name="winningNumber">The number (0-36) that the ball should land on</param>
|
||||||
/// <returns>A tuple containing the animation duration in seconds and the WebP animation bytes</returns>
|
/// <returns>A tuple containing the animation duration in seconds and the WebP animation bytes</returns>
|
||||||
public static (int durationSeconds, byte[] animationBytes) GenerateAnimation(int winningNumber)
|
public static async Task<(int duration, byte[])> GenerateAnimation(int winningNumber, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
if (winningNumber < 0 || winningNumber > 36)
|
if (winningNumber < 0 || winningNumber > 36)
|
||||||
{
|
{
|
||||||
@@ -994,7 +995,7 @@ public static class RouletteAnimationGenerator
|
|||||||
|
|
||||||
animation.Frames.RemoveFrame(0);
|
animation.Frames.RemoveFrame(0);
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
animation.SaveAsWebp(ms, new WebpEncoder { FileFormat = WebpFileFormatType.Lossy, Quality = 50 });
|
await animation.SaveAsWebpAsync(ms, new WebpEncoder { FileFormat = WebpFileFormatType.Lossy, Quality = 50 }, cancellationToken: ct);
|
||||||
|
|
||||||
return (duration, ms.ToArray());
|
return (duration, ms.ToArray());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ using KfChatDotNetBot.Models;
|
|||||||
using KfChatDotNetBot.Models.DbModels;
|
using KfChatDotNetBot.Models.DbModels;
|
||||||
using KfChatDotNetBot.Services;
|
using KfChatDotNetBot.Services;
|
||||||
using KfChatDotNetBot.Settings;
|
using KfChatDotNetBot.Settings;
|
||||||
using KfChatDotNetWsClient.Models.Events;
|
|
||||||
|
|
||||||
namespace KfChatDotNetBot.Commands.Kasino;
|
namespace KfChatDotNetBot.Commands.Kasino;
|
||||||
|
|
||||||
@@ -127,14 +126,14 @@ public class SlotsCommand : ICommand
|
|||||||
{
|
{
|
||||||
board.LoadAssets();
|
board.LoadAssets();
|
||||||
board.ExecuteGameLoop(spins, 0, rigged);
|
board.ExecuteGameLoop(spins, 0, rigged);
|
||||||
using (var finalImageStream = board.ExportAndCleanup())
|
await using (var finalImageStream = await board.ExportAndCleanup())
|
||||||
{
|
{
|
||||||
if (finalImageStream == null)
|
if (finalImageStream == null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("board.ExportAndCleanup returned null");
|
throw new InvalidOperationException("board.ExportAndCleanup returned null");
|
||||||
}
|
}
|
||||||
var imageUrl = await Zipline.Upload(finalImageStream, new MediaTypeHeaderValue("image/webp"), "1h", ctx);
|
var imageUrl = await Zipline.Upload(finalImageStream, new MediaTypeHeaderValue("image/webp"), "1h", ctx);
|
||||||
await botInstance.SendChatMessageAsync($"[img]{imageUrl}[/img]", true,
|
await botInstance.SendChatMessageAsync($"[spoiler=\"Slots game for {user.FormatUsername().Replace("\"", string.Empty)}\"][img]{imageUrl}[/img][/spoiler]", true,
|
||||||
autoDeleteAfter: TimeSpan.FromSeconds(60)); // delay till slots graphic deletion.
|
autoDeleteAfter: TimeSpan.FromSeconds(60)); // delay till slots graphic deletion.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +144,7 @@ public class SlotsCommand : ICommand
|
|||||||
delayHSec += board.AnimatedImage.Frames[i].Metadata.GetWebpMetadata().FrameDelay;
|
delayHSec += board.AnimatedImage.Frames[i].Metadata.GetWebpMetadata().FrameDelay;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Task.Delay(TimeSpan.FromSeconds(delayHSec));//adds delay to stop message showing gambling win/loss too early based on total frame count of the animated image
|
await Task.Delay(TimeSpan.FromSeconds(delayHSec), ctx);//adds delay to stop message showing gambling win/loss too early based on total frame count of the animated image
|
||||||
var colors =
|
var colors =
|
||||||
await SettingsProvider.GetMultipleValuesAsync([
|
await SettingsProvider.GetMultipleValuesAsync([
|
||||||
BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor
|
BuiltIn.Keys.KiwiFarmsGreenColor, BuiltIn.Keys.KiwiFarmsRedColor
|
||||||
@@ -157,7 +156,7 @@ public class SlotsCommand : ICommand
|
|||||||
{
|
{
|
||||||
newBalance = await Money.NewWagerAsync(gambler.Id, wager*spins, -wager*spins, WagerGame.Slots, ct: ctx);
|
newBalance = await Money.NewWagerAsync(gambler.Id, wager*spins, -wager*spins, WagerGame.Slots, ct: ctx);
|
||||||
var totalWager = wager * spins;
|
var totalWager = wager * spins;
|
||||||
await Task.Delay(TimeSpan.FromSeconds(spins));
|
await Task.Delay(TimeSpan.FromSeconds(spins), ctx);
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()} you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]lost[/color] {await totalWager.FormatKasinoCurrencyAsync()} with {spins} spins. Current balance: {await newBalance.FormatKasinoCurrencyAsync()}",
|
$"{user.FormatUsername()} you [color={colors[BuiltIn.Keys.KiwiFarmsRedColor].Value}]lost[/color] {await totalWager.FormatKasinoCurrencyAsync()} with {spins} spins. Current balance: {await newBalance.FormatKasinoCurrencyAsync()}",
|
||||||
true, autoDeleteAfter: TimeSpan.FromSeconds(30));
|
true, autoDeleteAfter: TimeSpan.FromSeconds(30));
|
||||||
@@ -185,7 +184,7 @@ public class SlotsCommand : ICommand
|
|||||||
await botInstance.BotServices.KasinoShop.ProcessWagerTracking(gambler, WagerGame.Slots, wager*spins, winnings, newBalance);
|
await botInstance.BotServices.KasinoShop.ProcessWagerTracking(gambler, WagerGame.Slots, wager*spins, winnings, newBalance);
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------
|
||||||
await Task.Delay(TimeSpan.FromSeconds(spins * 2));
|
await Task.Delay(TimeSpan.FromSeconds(spins * 2), ctx);
|
||||||
await botInstance.SendChatMessageAsync(
|
await botInstance.SendChatMessageAsync(
|
||||||
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]won[/color] {await rawWinnings.FormatKasinoCurrencyAsync()} from {spins} spins worth {await wager.FormatKasinoCurrencyAsync()}! Net: {winstr}{await winnings.FormatKasinoCurrencyAsync()} Current balance: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(30));
|
$"{user.FormatUsername()}, you [color={colors[BuiltIn.Keys.KiwiFarmsGreenColor].Value}]won[/color] {await rawWinnings.FormatKasinoCurrencyAsync()} from {spins} spins worth {await wager.FormatKasinoCurrencyAsync()}! Net: {winstr}{await winnings.FormatKasinoCurrencyAsync()} Current balance: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(30));
|
||||||
}
|
}
|
||||||
@@ -233,8 +232,11 @@ public class SlotsCommand : ICommand
|
|||||||
[(1, 0), (2, 1), (3, 2), (2, 3), (1, 4)]
|
[(1, 0), (2, 1), (3, 2), (2, 3), (1, 4)]
|
||||||
];
|
];
|
||||||
|
|
||||||
public KiwiSlotBoard(decimal bet)
|
private CancellationToken _ct;
|
||||||
|
|
||||||
|
public KiwiSlotBoard(decimal bet, CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
|
_ct = ct;
|
||||||
_userBet = bet;
|
_userBet = bet;
|
||||||
AnimatedImage = new Image<Rgba32>(600, 800);
|
AnimatedImage = new Image<Rgba32>(600, 800);
|
||||||
}
|
}
|
||||||
@@ -370,7 +372,7 @@ public class SlotsCommand : ICommand
|
|||||||
lastFrame.Metadata.GetWebpMetadata().FrameDelay = (ushort)hundredthsOfASecond;
|
lastFrame.Metadata.GetWebpMetadata().FrameDelay = (ushort)hundredthsOfASecond;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryStream? ExportAndCleanup()
|
public async Task<MemoryStream?> ExportAndCleanup()
|
||||||
{
|
{
|
||||||
if (AnimatedImage.Frames.Count <= 1) return null;
|
if (AnimatedImage.Frames.Count <= 1) return null;
|
||||||
|
|
||||||
@@ -378,7 +380,7 @@ public class SlotsCommand : ICommand
|
|||||||
// Remove the blank placeholder frame
|
// Remove the blank placeholder frame
|
||||||
AnimatedImage.Frames.RemoveFrame(0);
|
AnimatedImage.Frames.RemoveFrame(0);
|
||||||
|
|
||||||
AnimatedImage.Save(ms, new WebpEncoder { Quality = 80 });
|
await AnimatedImage.SaveAsync(ms, new WebpEncoder { Quality = 80 }, _ct);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
|
||||||
// Free the animation memory now that it's encoded
|
// Free the animation memory now that it's encoded
|
||||||
@@ -475,9 +477,8 @@ public class SlotsCommand : ICommand
|
|||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
for (var j = 0; j < 5; j++)
|
for (var j = 0; j < 5; j++)
|
||||||
{
|
{
|
||||||
var r = _rand.NextDouble() * 100.6;
|
var r = _rand.NextDouble() * 100.1;
|
||||||
if (f != 0 && j > 2) r *= 1.1;
|
if (f != 0 && j > 1) r *= 1.1;
|
||||||
if (rigged == 'L') r = _rand.NextDouble() * 97.01;
|
|
||||||
|
|
||||||
if (rigged == 'W') // guarantee max win
|
if (rigged == 'W') // guarantee max win
|
||||||
{
|
{
|
||||||
@@ -607,16 +608,16 @@ public class SlotsCommand : ICommand
|
|||||||
if (rigged == 'L') RigSlotBoard();
|
if (rigged == 'L') RigSlotBoard();
|
||||||
char PickSlotSymbol(double r, int i, int j)
|
char PickSlotSymbol(double r, int i, int j)
|
||||||
{
|
{
|
||||||
if (r < 22) return 'A';
|
if (r < 22.5) return 'A';
|
||||||
else if (r < 44) return 'B';
|
else if (r < 44.5) return 'B';
|
||||||
else if (r < 52) return 'C';
|
else if (r < 52.5) return 'C';
|
||||||
else if (r < 66) return 'D';
|
else if (r < 66.5) return 'D';
|
||||||
else if (r < 78) return 'E';
|
else if (r < 78.5) return 'E';
|
||||||
else if (r < 84) return 'F';
|
else if (r < 84.5) return 'F';
|
||||||
else if (r < 89) return 'G';
|
else if (r < 89.5) return 'G';
|
||||||
else if (r < 92) return 'H';
|
else if (r < 92.5) return 'H';
|
||||||
else if (r < 95) return 'I';
|
else if (r < 95.5) return 'I';
|
||||||
else if (r < 97) return 'J';
|
else if (r < 97.5) return 'J';
|
||||||
else if (r < 98.5) return WILD;
|
else if (r < 98.5) return WILD;
|
||||||
else if (r < (j <= 2 ? 99 : 99.5)) { if (!ex.Contains(j)) { return EXPANDER; } else return WILD; }
|
else if (r < (j <= 2 ? 99 : 99.5)) { if (!ex.Contains(j)) { return EXPANDER; } else return WILD; }
|
||||||
else { if (fc < 5) { fc++;
|
else { if (fc < 5) { fc++;
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public class XeetEmbedCommand : ICommand
|
|||||||
|
|
||||||
var ffmpegPath = await SettingsProvider.GetValueAsync(BuiltIn.Keys.FFmpegBinaryPath);
|
var ffmpegPath = await SettingsProvider.GetValueAsync(BuiltIn.Keys.FFmpegBinaryPath);
|
||||||
|
|
||||||
var ffmpegArgs = $"-i \"{tempVideoPath}\" -vf \"fps=10,scale='min(640,iw)':'min(480,ih)':force_original_aspect_ratio=decrease\" -c:v libwebp -lossless 0 -quality 75 -loop 0 -an \"{tempWebpPath}\"";
|
var ffmpegArgs = $"-i \"{tempVideoPath}\" -vf \"fps=20,scale='min(640,iw)':'min(480,ih)':force_original_aspect_ratio=decrease\" -c:v libwebp -threads 4 -lossless 0 -quality 75 -loop 0 -an \"{tempWebpPath}\"";
|
||||||
|
|
||||||
var processInfo = new ProcessStartInfo
|
var processInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
@@ -339,10 +339,19 @@ public class XeetEmbedCommand : ICommand
|
|||||||
|
|
||||||
if (mediaUrls.Count > 0)
|
if (mediaUrls.Count > 0)
|
||||||
{
|
{
|
||||||
|
if (mediaUrls.Count >= 2)
|
||||||
|
{
|
||||||
|
bodyBuilder.Append("[spoiler=\"Media attachments\"]");
|
||||||
|
}
|
||||||
foreach (var mediaUrl in mediaUrls)
|
foreach (var mediaUrl in mediaUrls)
|
||||||
{
|
{
|
||||||
bodyBuilder.Append($"[img]{mediaUrl}[/img][br]");
|
bodyBuilder.Append($"[img]{mediaUrl}[/img]");
|
||||||
}
|
}
|
||||||
|
if (mediaUrls.Count > 2)
|
||||||
|
{
|
||||||
|
bodyBuilder.Append("[/spoiler]");
|
||||||
|
}
|
||||||
|
bodyBuilder.Append("[br]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle quote tweet (if this tweet quotes another)
|
// Handle quote tweet (if this tweet quotes another)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using KfChatDotNetBot.Models.DbModels;
|
using KfChatDotNetBot.Models.DbModels;
|
||||||
|
|
||||||
@@ -137,4 +138,45 @@ public static class Extensions
|
|||||||
{
|
{
|
||||||
return $"@{user.KfUsername}";
|
return $"@{user.KfUsername}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Format a grid of equally spaced text into a table so it can be shrunk safely by prepending a [size] tag
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">Grid you want to format</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GridToTable(this string s)
|
||||||
|
{
|
||||||
|
var table = "[table width=\"1%\"]";
|
||||||
|
foreach (var row in s.Split(["[br]", "[BR]", "\n"], StringSplitOptions.None))
|
||||||
|
{
|
||||||
|
table += "[tr]";
|
||||||
|
var enumerator = StringInfo.GetTextElementEnumerator(row);
|
||||||
|
while (enumerator.MoveNext())
|
||||||
|
{
|
||||||
|
table += $"[td]{enumerator.Current}[/td]";
|
||||||
|
}
|
||||||
|
table += "[/tr]";
|
||||||
|
}
|
||||||
|
|
||||||
|
table += "[/table]";
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Format a string with multiple lines of text into a table so it can be shrunk without ugly spacing issues by prepending a [size] tag
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">Multi-line text you want to format</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string MultilineToTable(this string s)
|
||||||
|
{
|
||||||
|
// No width on this one or it'll wrap text
|
||||||
|
var table = "[table]";
|
||||||
|
// Never use a th instead of a tr as it has a more prominent text style
|
||||||
|
foreach (var row in s.Split(["[br]", "[BR]", "\n"], StringSplitOptions.None))
|
||||||
|
{
|
||||||
|
table += $"[tr][td]{row}[/td][/tr]";
|
||||||
|
}
|
||||||
|
table += "[/table]";
|
||||||
|
return table;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,636 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using KfChatDotNetBot;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20260510073657_AddImageTags")]
|
||||||
|
partial class AddImageTags
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Currency")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("CurrencyPrice")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("GameTitle")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Updated")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Win")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Winnings")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChipsggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Balance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("NextVipLevelWagerRequirement")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RandomSeed")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("TotalWagered")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Gamblers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Expires")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Source")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Exclusions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal?>("Payout")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PerkName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PerkTier")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PerkType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Perks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.HowlggBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Bet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BetId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Date")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Game")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Profit")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("HowlggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ImageDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Tags")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("JuicedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Juicers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Moms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.RainbetBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("BetSeenAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("GameName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Payout")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("PublicId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RainbetUserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RainbetBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.SettingDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("CacheDuration")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Default")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSecret")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Regex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ValueType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoCapture")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Service")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("StreamUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Streams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("Effect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventSource")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("FromId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("NewBalance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("FromId");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Transactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TwitchViewCountDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("ServerTime")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Topic")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Viewers")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("TwitchViewCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Ignored")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("KfId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("KfUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserRight")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("FirstOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LatestOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("UsersWhoWere");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Game")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("GameMeta")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsComplete")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Multiplier")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerAmount")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerEffect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Wagers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "From")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FromId");
|
||||||
|
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("From");
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddImageTags : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Tags",
|
||||||
|
table: "Images",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Tags",
|
||||||
|
table: "Images");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,640 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using KfChatDotNetBot;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20260510172529_ImageTagList")]
|
||||||
|
partial class ImageTagList
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Currency")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("CurrencyPrice")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("GameTitle")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Updated")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Win")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Winnings")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChipsggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Balance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("NextVipLevelWagerRequirement")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RandomSeed")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("TotalWagered")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Gamblers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Expires")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Source")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Exclusions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal?>("Payout")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PerkName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PerkTier")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PerkType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Perks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.HowlggBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Bet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BetId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Date")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Game")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Profit")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("HowlggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ImageDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("TagList")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Tags")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("JuicedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Juicers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Moms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.RainbetBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("BetSeenAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("GameName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Payout")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("PublicId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RainbetUserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RainbetBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.SettingDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("CacheDuration")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Default")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSecret")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Regex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ValueType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoCapture")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Service")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("StreamUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Streams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("Effect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventSource")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("FromId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("NewBalance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("FromId");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Transactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TwitchViewCountDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("ServerTime")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Topic")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Viewers")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("TwitchViewCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Ignored")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("KfId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("KfUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserRight")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("FirstOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LatestOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("UsersWhoWere");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Game")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("GameMeta")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsComplete")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Multiplier")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerAmount")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerEffect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Wagers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "From")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FromId");
|
||||||
|
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("From");
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ImageTagList : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "TagList",
|
||||||
|
table: "Images",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "TagList",
|
||||||
|
table: "Images");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,665 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using KfChatDotNetBot;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
|
[Migration("20260510194844_ImageMetadata")]
|
||||||
|
partial class ImageMetadata
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Currency")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("CurrencyPrice")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("GameTitle")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Updated")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Win")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Winnings")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ChipsggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Balance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("NextVipLevelWagerRequirement")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("RandomSeed")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("State")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("TotalWagered")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Gamblers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Created")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Expires")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Source")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Exclusions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal?>("Payout")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("PerkName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PerkTier")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PerkType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Perks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.HowlggBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Bet")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BetId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Date")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Game")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("GameId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<long>("Profit")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("HowlggBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ImageDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("TagList")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Tags")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Url")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Images");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<float>("Amount")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("JuicedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Juicers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Moms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.RainbetBetsDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("BetId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("BetSeenAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("GameName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Multiplier")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<float>("Payout")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("PublicId")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("RainbetUserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<float>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("RainbetBets");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.SettingDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("CacheDuration")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Default")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsSecret")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Regex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ValueType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Settings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoCapture")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Service")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("StreamUrl")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Streams");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("Effect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("EventSource")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("FromId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("NewBalance")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("FromId");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Transactions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TwitchViewCountDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("ServerTime")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Topic")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Viewers")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("TwitchViewCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("Ignored")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("KfId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("KfUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserRight")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("FirstOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LatestOccurence")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("UsersWhoWere");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GamblerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Game")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("GameMeta")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsComplete")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("Multiplier")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<long>("TimeUnixEpochSeconds")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerAmount")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal>("WagerEffect")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GamblerId");
|
||||||
|
|
||||||
|
b.ToTable("Wagers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerExclusionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.GamblerPerkDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ImageDbModel", b =>
|
||||||
|
{
|
||||||
|
b.OwnsOne("KfChatDotNetBot.Models.DbModels.ImageMetadataModel", "Metadata", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<int>("ImageDbModelId");
|
||||||
|
|
||||||
|
b1.Property<int>("AddedByUserId");
|
||||||
|
|
||||||
|
b1.Property<DateTimeOffset>("WhenAdded");
|
||||||
|
|
||||||
|
b1.HasKey("ImageDbModelId");
|
||||||
|
|
||||||
|
b1.ToTable("Images");
|
||||||
|
|
||||||
|
b1
|
||||||
|
.ToJson("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("ImageDbModelId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("Metadata");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.MomDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.StreamDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.TransactionDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "From")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("FromId");
|
||||||
|
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("From");
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.UserWhoWasDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.WagerDbModel", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("KfChatDotNetBot.Models.DbModels.GamblerDbModel", "Gambler")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GamblerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Gambler");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace KfChatDotNetBot.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ImageMetadata : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Metadata",
|
||||||
|
table: "Images",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Metadata",
|
||||||
|
table: "Images");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace KfChatDotNetBot.Migrations
|
|||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.4");
|
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||||
|
|
||||||
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b =>
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ChipsggBetDbModel", b =>
|
||||||
{
|
{
|
||||||
@@ -212,6 +212,13 @@ namespace KfChatDotNetBot.Migrations
|
|||||||
b.Property<DateTimeOffset>("LastSeen")
|
b.Property<DateTimeOffset>("LastSeen")
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.PrimitiveCollection<string>("TagList")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Tags")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<string>("Url")
|
b.Property<string>("Url")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("TEXT");
|
.HasColumnType("TEXT");
|
||||||
@@ -555,6 +562,31 @@ namespace KfChatDotNetBot.Migrations
|
|||||||
b.Navigation("Gambler");
|
b.Navigation("Gambler");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.ImageDbModel", b =>
|
||||||
|
{
|
||||||
|
b.OwnsOne("KfChatDotNetBot.Models.DbModels.ImageMetadataModel", "Metadata", b1 =>
|
||||||
|
{
|
||||||
|
b1.Property<int>("ImageDbModelId");
|
||||||
|
|
||||||
|
b1.Property<int>("AddedByUserId");
|
||||||
|
|
||||||
|
b1.Property<DateTimeOffset>("WhenAdded");
|
||||||
|
|
||||||
|
b1.HasKey("ImageDbModelId");
|
||||||
|
|
||||||
|
b1.ToTable("Images");
|
||||||
|
|
||||||
|
b1
|
||||||
|
.ToJson("Metadata")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b1.WithOwner()
|
||||||
|
.HasForeignKey("ImageDbModelId");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.Navigation("Metadata");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
modelBuilder.Entity("KfChatDotNetBot.Models.DbModels.JuicerDbModel", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
b.HasOne("KfChatDotNetBot.Models.DbModels.UserDbModel", "User")
|
||||||
|
|||||||
@@ -6,4 +6,29 @@ public class ImageDbModel
|
|||||||
public required string Key { get; set; }
|
public required string Key { get; set; }
|
||||||
public required string Url { get; set; }
|
public required string Url { get; set; }
|
||||||
public required DateTimeOffset LastSeen { get; set; }
|
public required DateTimeOffset LastSeen { get; set; }
|
||||||
|
[Obsolete("Use TagList instead")]
|
||||||
|
public string? Tags { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// List of image tags for recalling specific images
|
||||||
|
/// </summary>
|
||||||
|
public required List<string> TagList { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JSON object containing whatever bullshit metadata we want to attach to this image
|
||||||
|
/// Value will be null for images that were added prior to metadata being introduced
|
||||||
|
/// </summary>
|
||||||
|
public required ImageMetadataModel? Metadata { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageMetadataModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// User ID (IN THE BOT, NOT KIWI FARMS USER ID) of whoever added this image
|
||||||
|
/// </summary>
|
||||||
|
public required int AddedByUserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When the image was added to the database
|
||||||
|
/// </summary>
|
||||||
|
public required DateTimeOffset WhenAdded { get; set; }
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using KfChatDotNetBot.Migrations;
|
||||||
|
using KfChatDotNetBot.Services;
|
||||||
using KfChatDotNetBot.Settings;
|
using KfChatDotNetBot.Settings;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NLog;
|
using NLog;
|
||||||
@@ -38,9 +40,34 @@ namespace KfChatDotNetBot
|
|||||||
await BuiltIn.SyncSettingsWithDb();
|
await BuiltIn.SyncSettingsWithDb();
|
||||||
logger.Info("Migrating settings from config.json (if needed)");
|
logger.Info("Migrating settings from config.json (if needed)");
|
||||||
await BuiltIn.MigrateJsonSettingsToDb();
|
await BuiltIn.MigrateJsonSettingsToDb();
|
||||||
|
logger.Info("Attempting to grab the Redis connection multiplexer so it's built");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = Redis.Multiplexer;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error("Caught an error when attempting to grab the Redis multiplexer");
|
||||||
|
logger.Error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await db.Images.AnyAsync())
|
||||||
|
{
|
||||||
|
logger.Info("Checking to see if we need to migrate Tags to TagList");
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
var scope = (await db.Images.Where(i => i.Tags != null).ToListAsync()).Where(i => i.TagList.Count == 0).ToList();
|
||||||
|
foreach (var item in scope)
|
||||||
|
{
|
||||||
|
// Ignoring the null as my query literally filters for != null
|
||||||
|
item.TagList = item.Tags!.Split(" ").ToList();
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
logger.Info($"Migrated tags for image {item.Id}");
|
||||||
|
}
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
logger.Info("Handing over to bot now");
|
logger.Info("Handing over to bot now");
|
||||||
Console.OutputEncoding = Encoding.UTF8;
|
Console.OutputEncoding = Encoding.UTF8;
|
||||||
new ChatBot();
|
_ = new ChatBot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,16 +42,16 @@ internal class BotCommands
|
|||||||
|
|
||||||
internal void ProcessMessage(BotCommandMessageModel message)
|
internal void ProcessMessage(BotCommandMessageModel message)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(message.MessageRaw))
|
if (string.IsNullOrEmpty(message.MessageRawHtmlDecoded))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var messageTrimmed = message.MessageRaw.TrimStart(CommandPrefix);
|
var messageTrimmed = message.MessageRawHtmlDecoded.TrimStart(CommandPrefix);
|
||||||
foreach (var command in Commands)
|
foreach (var command in Commands)
|
||||||
{
|
{
|
||||||
var noPrefixCommand = HasAttribute<NoPrefixRequired>(command);
|
var noPrefixCommand = HasAttribute<NoPrefixRequired>(command);
|
||||||
if (!noPrefixCommand && !message.MessageRaw.StartsWith(CommandPrefix)) continue;
|
if (!noPrefixCommand && !message.MessageRawHtmlDecoded.StartsWith(CommandPrefix)) continue;
|
||||||
foreach (var regex in command.Patterns)
|
foreach (var regex in command.Patterns)
|
||||||
{
|
{
|
||||||
var match = regex.Match(messageTrimmed);
|
var match = regex.Match(messageTrimmed);
|
||||||
|
|||||||
@@ -390,12 +390,13 @@ public class BotServices
|
|||||||
_logger.Info("Built the almanac shill task");
|
_logger.Info("Built the almanac shill task");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task BuildDLiveStatusCheck()
|
private async Task BuildDLiveStatusCheck()
|
||||||
{
|
{
|
||||||
|
var enabled = (await SettingsProvider.GetValueAsync(BuiltIn.Keys.DLiveEnabled)).ToBoolean();
|
||||||
|
if (!enabled) return;
|
||||||
_dliveStatusCheck = new DLive(_chatBot);
|
_dliveStatusCheck = new DLive(_chatBot);
|
||||||
_dliveStatusCheck.StartLiveStatusCheck();
|
_dliveStatusCheck.StartLiveStatusCheck();
|
||||||
_logger.Info("Built the DLive livestream status check task");
|
_logger.Info("Built the DLive livestream status check task");
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task BuildPeerTubeLiveStatusCheck()
|
private Task BuildPeerTubeLiveStatusCheck()
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ public class KasinoKrash : IDisposable
|
|||||||
await _kfChatBot.SendChatMessageAsync(
|
await _kfChatBot.SendChatMessageAsync(
|
||||||
$"{bet.Gambler.User.FormatUsername()}, due to your poor gambling skills, your bet was scaled down to {await bet.Wager.FormatKasinoCurrencyAsync()} to match your remaining balance.",
|
$"{bet.Gambler.User.FormatUsername()}, due to your poor gambling skills, your bet was scaled down to {await bet.Wager.FormatKasinoCurrencyAsync()} to match your remaining balance.",
|
||||||
true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
true, autoDeleteAfter: TimeSpan.FromSeconds(10));
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bet.Multi <= TheGame.FinalMulti && bet.Multi != -1)
|
else if (bet.Multi <= TheGame.FinalMulti && bet.Multi != -1)
|
||||||
|
|||||||
@@ -298,7 +298,11 @@ public class KasinoMines
|
|||||||
{
|
{
|
||||||
await GetSavedGames(gamblerId);
|
await GetSavedGames(gamblerId);
|
||||||
//attempt to delete the message if its there
|
//attempt to delete the message if its there
|
||||||
if (ActiveGames[gamblerId].LastMessageId != null) await _kfChatBot.KfClient.DeleteMessageAsync(ActiveGames[gamblerId].LastMessageId!);
|
var lastMsgId = ActiveGames[gamblerId].LastMessageId;
|
||||||
|
if (lastMsgId != null)
|
||||||
|
{
|
||||||
|
_kfChatBot.ScheduleMessageAutoDelete(lastMsgId, TimeSpan.FromSeconds(15));
|
||||||
|
}
|
||||||
ActiveGames.Remove(gamblerId);
|
ActiveGames.Remove(gamblerId);
|
||||||
await SaveActiveGames(gamblerId);
|
await SaveActiveGames(gamblerId);
|
||||||
}
|
}
|
||||||
@@ -337,7 +341,6 @@ public class KasinoMines
|
|||||||
|
|
||||||
await _kfChatBot.SendChatMessageAsync(
|
await _kfChatBot.SendChatMessageAsync(
|
||||||
$"{game.Creator.User.FormatUsername()}, you won {await payout.FormatKasinoCurrencyAsync()} from your {await game.Wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.BetsPlaced.Count} gems while avoiding {game.Mines} mines. Net: {await net.FormatKasinoCurrencyAsync()}. Balance: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
$"{game.Creator.User.FormatUsername()}, you won {await payout.FormatKasinoCurrencyAsync()} from your {await game.Wager.FormatKasinoCurrencyAsync()} bet on mines, collecting {game.BetsPlaced.Count} gems while avoiding {game.Mines} mines. Net: {await net.FormatKasinoCurrencyAsync()}. Balance: {await newBalance.FormatKasinoCurrencyAsync()}", true, autoDeleteAfter: TimeSpan.FromSeconds(15));
|
||||||
await Task.Delay(TimeSpan.FromSeconds(15));
|
|
||||||
await RemoveGame(game.Creator.Id);
|
await RemoveGame(game.Creator.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -586,6 +586,15 @@ public static class BuiltIn
|
|||||||
public static string WinnaBmjUsername = "Winna.BmjUsername";
|
public static string WinnaBmjUsername = "Winna.BmjUsername";
|
||||||
[BuiltInSetting("Array of cookies as a shitty hack to get Winna going", SettingValueType.Array, "[]")]
|
[BuiltInSetting("Array of cookies as a shitty hack to get Winna going", SettingValueType.Array, "[]")]
|
||||||
public static string WinnaCookies = "Winna.Cookies";
|
public static string WinnaCookies = "Winna.Cookies";
|
||||||
|
[BuiltInSetting("Whether the DLive livestream check is enabled", SettingValueType.Boolean, "false",
|
||||||
|
BooleanRegex)]
|
||||||
|
public static string DLiveEnabled = "DLive.Enabled";
|
||||||
|
[BuiltInSetting("Size (%) of the Keno board", SettingValueType.Text, "70", WholeNumberRegex)]
|
||||||
|
public static string KasinoKenoSize = "Kasino.Keno.Size";
|
||||||
|
[BuiltInSetting("Size (%) of the Planes board", SettingValueType.Text, "70", WholeNumberRegex)]
|
||||||
|
public static string KasinoPlanesSize = "Kasino.Planes.Size";
|
||||||
|
[BuiltInSetting("Size (%) of the Plinko board", SettingValueType.Text, "70", WholeNumberRegex)]
|
||||||
|
public static string KasinoPlinkoSize = "Kasino.Plinko.Size";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user