finalized rewritten xp loop, updated xp.yml
This commit is contained in:
parent
dbc312dd9d
commit
06970eb9d3
15 changed files with 487 additions and 526 deletions
src/EllieBot
Modules/Xp
Services/GrpcApi
_common/Abstractions/Cache
data
14
src/EllieBot/Modules/Xp/Db/UserXpBatch.cs
Normal file
14
src/EllieBot/Modules/Xp/Db/UserXpBatch.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
#nullable disable warnings
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace EllieBot.Modules.Xp.Services;
|
||||
|
||||
public sealed class UserXpBatch
|
||||
{
|
||||
[Key]
|
||||
public ulong UserId { get; set; }
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string AvatarId { get; set; } = string.Empty;
|
||||
}
|
|
@ -31,11 +31,13 @@ public partial class Xp : EllieModule<XpService>
|
|||
|
||||
private readonly DownloadTracker _tracker;
|
||||
private readonly ICurrencyProvider _gss;
|
||||
private readonly XpTemplateService _templateService;
|
||||
|
||||
public Xp(DownloadTracker tracker, ICurrencyProvider gss)
|
||||
public Xp(DownloadTracker tracker, ICurrencyProvider gss, XpTemplateService templateService)
|
||||
{
|
||||
_tracker = tracker;
|
||||
_gss = gss;
|
||||
_templateService = templateService;
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
|
@ -325,7 +327,7 @@ public partial class Xp : EllieModule<XpService>
|
|||
[OwnerOnly]
|
||||
public async Task XpTemplateReload()
|
||||
{
|
||||
_service.ReloadXpTemplate();
|
||||
_templateService.ReloadXpTemplate();
|
||||
await Task.Delay(1000);
|
||||
await Response().Confirm(strs.template_reloaded).SendAsync();
|
||||
}
|
||||
|
|
|
@ -10,25 +10,19 @@ namespace EllieBot.Modules.Xp;
|
|||
public sealed partial class XpConfig : ICloneable<XpConfig>
|
||||
{
|
||||
[Comment("""DO NOT CHANGE""")]
|
||||
public int Version { get; set; } = 7;
|
||||
public int Version { get; set; } = 10;
|
||||
|
||||
[Comment("""How much XP will the users receive per message""")]
|
||||
public int XpPerMessage { get; set; } = 3;
|
||||
public int TextXpPerMessage { get; set; } = 3;
|
||||
|
||||
[Comment("""How often can the users receive XP, in seconds""")]
|
||||
public float MessageXpCooldown { get; set; } = 300;
|
||||
public int TextXpCooldown { get; set; } = 300;
|
||||
|
||||
[Comment("""Amount of xp users gain from posting an image""")]
|
||||
public int XpFromImage { get; set; } = 0;
|
||||
public int TextXpFromImage { get; set; } = 3;
|
||||
|
||||
[Comment("""Average amount of xp earned per minute in VC""")]
|
||||
public double VoiceXpPerMinute { get; set; } = 0;
|
||||
|
||||
[Comment("""The maximum amount of minutes the bot will keep track of a user in a voice channel""")]
|
||||
public int VoiceMaxMinutes { get; set; } = 720;
|
||||
|
||||
[Comment("""The amount of currency users will receive for each point of global xp that they earn""")]
|
||||
public float CurrencyPerXp { get; set; } = 0;
|
||||
public int VoiceXpPerMinute { get; set; } = 3;
|
||||
|
||||
[Comment("""Xp Shop config""")]
|
||||
public ShopConfig Shop { get; set; } = new();
|
||||
|
@ -36,44 +30,44 @@ public sealed partial class XpConfig : ICloneable<XpConfig>
|
|||
public sealed class ShopConfig
|
||||
{
|
||||
[Comment("""
|
||||
Whether the xp shop is enabled
|
||||
True -> Users can access the xp shop using .xpshop command
|
||||
False -> Users can't access the xp shop
|
||||
""")]
|
||||
Whether the xp shop is enabled
|
||||
True -> Users can access the xp shop using .xpshop command
|
||||
False -> Users can't access the xp shop
|
||||
""")]
|
||||
public bool IsEnabled { get; set; } = false;
|
||||
|
||||
[Comment("""
|
||||
Which patron tier do users need in order to use the .xpshop bgs command
|
||||
Leave at 'None' if patron system is disabled or you don't want any restrictions
|
||||
""")]
|
||||
Which patron tier do users need in order to use the .xpshop bgs command
|
||||
Leave at 'None' if patron system is disabled or you don't want any restrictions
|
||||
""")]
|
||||
public PatronTier BgsTierRequirement { get; set; } = PatronTier.None;
|
||||
|
||||
|
||||
[Comment("""
|
||||
Which patron tier do users need in order to use the .xpshop frames command
|
||||
Leave at 'None' if patron system is disabled or you don't want any restrictions
|
||||
""")]
|
||||
Which patron tier do users need in order to use the .xpshop frames command
|
||||
Leave at 'None' if patron system is disabled or you don't want any restrictions
|
||||
""")]
|
||||
public PatronTier FramesTierRequirement { get; set; } = PatronTier.None;
|
||||
|
||||
|
||||
[Comment("""
|
||||
Frames available for sale. Keys are unique IDs.
|
||||
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
|
||||
Removing a key which previously existed means that all previous purchases will also be unusable.
|
||||
To remove an item from the shop, but keep previous purchases, set the price to -1
|
||||
""")]
|
||||
Frames available for sale. Keys are unique IDs.
|
||||
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
|
||||
Removing a key which previously existed means that all previous purchases will also be unusable.
|
||||
To remove an item from the shop, but keep previous purchases, set the price to -1
|
||||
""")]
|
||||
public Dictionary<string, ShopItemInfo>? Frames { get; set; } = new()
|
||||
{
|
||||
{"default", new() {Name = "No frame", Price = 0, Url = string.Empty}}
|
||||
{ "default", new() { Name = "No frame", Price = 0, Url = string.Empty } }
|
||||
};
|
||||
|
||||
[Comment("""
|
||||
Backgrounds available for sale. Keys are unique IDs.
|
||||
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
|
||||
Removing a key which previously existed means that all previous purchases will also be unusable.
|
||||
To remove an item from the shop, but keep previous purchases, set the price to -1
|
||||
""")]
|
||||
Backgrounds available for sale. Keys are unique IDs.
|
||||
Do not change keys as they are not publicly visible. Only change properties (name, price, id)
|
||||
Removing a key which previously existed means that all previous purchases will also be unusable.
|
||||
To remove an item from the shop, but keep previous purchases, set the price to -1
|
||||
""")]
|
||||
public Dictionary<string, ShopItemInfo>? Bgs { get; set; } = new()
|
||||
{
|
||||
{"default", new() {Name = "Default Background", Price = 0, Url = string.Empty}}
|
||||
{ "default", new() { Name = "Default Background", Price = 0, Url = string.Empty } }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -81,16 +75,17 @@ public sealed partial class XpConfig : ICloneable<XpConfig>
|
|||
{
|
||||
[Comment("""Visible name of the item""")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Comment("""Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase""")]
|
||||
|
||||
[Comment(
|
||||
"""Price of the item. Set to -1 if you no longer want to sell the item but want the users to be able to keep their old purchase""")]
|
||||
public int Price { get; set; }
|
||||
|
||||
|
||||
[Comment("""Direct url to the .png image which will be applied to the user's XP card""")]
|
||||
public string Url { get; set; }
|
||||
|
||||
|
||||
[Comment("""Optional preview url which will show instead of the real URL in the shop """)]
|
||||
public string Preview { get; set; }
|
||||
|
||||
|
||||
[Comment("""Optional description of the item""")]
|
||||
public string Desc { get; set; }
|
||||
}
|
||||
|
|
|
@ -15,24 +15,29 @@ public sealed class XpConfigService : ConfigServiceBase<XpConfig>
|
|||
: base(FILE_PATH, serializer, pubSub, _changeKey)
|
||||
{
|
||||
AddParsedProp("txt.cooldown",
|
||||
conf => conf.MessageXpCooldown,
|
||||
float.TryParse,
|
||||
conf => conf.TextXpCooldown,
|
||||
int.TryParse,
|
||||
(f) => f.ToString("F2"),
|
||||
x => x > 0);
|
||||
AddParsedProp("txt.per_msg", conf => conf.XpPerMessage, int.TryParse, ConfigPrinters.ToString, x => x >= 0);
|
||||
AddParsedProp("txt.per_image", conf => conf.XpFromImage, int.TryParse, ConfigPrinters.ToString, x => x > 0);
|
||||
|
||||
AddParsedProp("voice.per_minute",
|
||||
conf => conf.VoiceXpPerMinute,
|
||||
double.TryParse,
|
||||
AddParsedProp("txt.permsg",
|
||||
conf => conf.TextXpPerMessage,
|
||||
int.TryParse,
|
||||
ConfigPrinters.ToString,
|
||||
x => x >= 0);
|
||||
AddParsedProp("voice.max_minutes",
|
||||
conf => conf.VoiceMaxMinutes,
|
||||
|
||||
AddParsedProp("txt.perimage",
|
||||
conf => conf.TextXpFromImage,
|
||||
int.TryParse,
|
||||
ConfigPrinters.ToString,
|
||||
x => x > 0);
|
||||
|
||||
AddParsedProp("voice.perminute",
|
||||
conf => conf.VoiceXpPerMinute,
|
||||
int.TryParse,
|
||||
ConfigPrinters.ToString,
|
||||
x => x >= 0);
|
||||
|
||||
AddParsedProp("shop.is_enabled",
|
||||
conf => conf.Shop.IsEnabled,
|
||||
bool.TryParse,
|
||||
|
@ -43,21 +48,11 @@ public sealed class XpConfigService : ConfigServiceBase<XpConfig>
|
|||
|
||||
private void Migrate()
|
||||
{
|
||||
if (data.Version < 2)
|
||||
if (data.Version < 10)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 2;
|
||||
c.XpFromImage = 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (data.Version < 7)
|
||||
{
|
||||
ModifyConfig(c =>
|
||||
{
|
||||
c.Version = 7;
|
||||
c.MessageXpCooldown *= 60;
|
||||
c.Version = 10;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,8 +7,8 @@ namespace EllieBot.Modules.Xp;
|
|||
|
||||
public class XpTemplate
|
||||
{
|
||||
public int Version { get; set; } = 0;
|
||||
|
||||
public int Version { get; set; } = 2;
|
||||
|
||||
[JsonProperty("output_size")]
|
||||
public XpTemplatePos OutputSize { get; set; } = new()
|
||||
{
|
|
@ -217,7 +217,7 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
|
|||
throw new RpcException(new Status(StatusCode.NotFound, "Guild not found"));
|
||||
|
||||
var data = await _xp.GetGuildUserXps(request.GuildId, request.Page - 1);
|
||||
var total = await _xp.GetTotalGuildUsers(request.GuildId);
|
||||
var total = await _xp.GetGuildXpUsersCountAsync(request.GuildId);
|
||||
|
||||
var reply = new GetXpLbReply
|
||||
{
|
||||
|
|
|
@ -9,12 +9,12 @@ namespace Ellie.Common;
|
|||
public sealed class MemoryBotCache : IBotCache
|
||||
{
|
||||
// needed for overwrites and Delete return value
|
||||
private readonly object _cacheLock = new object();
|
||||
private readonly ConcurrentDictionary<string, object> _locks = new();
|
||||
private readonly MemoryCache _cache;
|
||||
|
||||
public MemoryBotCache()
|
||||
{
|
||||
_cache = new MemoryCache(new MemoryCacheOptions());
|
||||
_cache = new(new MemoryCacheOptions());
|
||||
}
|
||||
|
||||
public ValueTask<bool> AddAsync<T>(TypedKey<T> key, T value, TimeSpan? expiry = null, bool overwrite = true)
|
||||
|
@ -26,12 +26,14 @@ public sealed class MemoryBotCache : IBotCache
|
|||
item.AbsoluteExpirationRelativeToNow = expiry;
|
||||
return new(true);
|
||||
}
|
||||
|
||||
lock (_cacheLock)
|
||||
|
||||
var cacheLock = _locks.GetOrAdd(key.Key, static _ => new());
|
||||
|
||||
lock (cacheLock)
|
||||
{
|
||||
if (_cache.TryGetValue(key.Key, out var old) && old is not null)
|
||||
return new(false);
|
||||
|
||||
|
||||
using var item = _cache.CreateEntry(key.Key);
|
||||
item.Value = value;
|
||||
item.AbsoluteExpirationRelativeToNow = expiry;
|
||||
|
@ -61,9 +63,10 @@ public sealed class MemoryBotCache : IBotCache
|
|||
|
||||
public ValueTask<bool> RemoveAsync<T>(TypedKey<T> key)
|
||||
{
|
||||
lock (_cacheLock)
|
||||
var cacheLock = _locks.GetOrAdd(key.Key, static _ => new());
|
||||
lock (cacheLock)
|
||||
{
|
||||
var toReturn = _cache.TryGetValue(key.Key, out var old ) && old is not null;
|
||||
var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null;
|
||||
_cache.Remove(key.Key);
|
||||
return new(toReturn);
|
||||
}
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
# DO NOT CHANGE
|
||||
version: 7
|
||||
version: 10
|
||||
# How much XP will the users receive per message
|
||||
xpPerMessage: 3
|
||||
textXpPerMessage: 3
|
||||
# How often can the users receive XP, in seconds
|
||||
messageXpCooldown: 300
|
||||
textXpCooldown: 300
|
||||
# Amount of xp users gain from posting an image
|
||||
xpFromImage: 0
|
||||
textXpFromImage: 3
|
||||
# Average amount of xp earned per minute in VC
|
||||
voiceXpPerMinute: 0
|
||||
# The maximum amount of minutes the bot will keep track of a user in a voice channel
|
||||
voiceMaxMinutes: 720
|
||||
# The amount of currency users will receive for each point of global xp that they earn
|
||||
currencyPerXp: 0
|
||||
# Xp Shop config
|
||||
shop:
|
||||
# Whether the xp shop is enabled
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"Version": 2,
|
||||
"output_size": {
|
||||
"X": 800,
|
||||
"Y": 392
|
||||
|
|
Loading…
Add table
Reference in a new issue