mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
- Moved update loop to a separate method.
- Added optimize flag to GlobalNadeko configuration. - Added some packages which will be needed soon
This commit is contained in:
@@ -121,153 +121,155 @@ public class XpService : INService, IReadyExecutor
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
=> UpdateLoop();
|
|
||||||
|
|
||||||
private async Task UpdateLoop()
|
|
||||||
{
|
{
|
||||||
using var timer = new PeriodicTimer(5.Seconds());
|
using var timer = new PeriodicTimer(5.Seconds());
|
||||||
while (await timer.WaitForNextTickAsync())
|
while (await timer.WaitForNextTickAsync())
|
||||||
{
|
{
|
||||||
try
|
await UpdateLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateLoop()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toNotify =
|
||||||
|
new List<(IGuild Guild, IMessageChannel MessageChannel, IUser User, int Level,
|
||||||
|
XpNotificationLocation NotifyType, NotifOf NotifOf)>();
|
||||||
|
var roleRewards = new Dictionary<ulong, List<XpRoleReward>>();
|
||||||
|
var curRewards = new Dictionary<ulong, List<XpCurrencyReward>>();
|
||||||
|
|
||||||
|
var toAddTo = new List<UserCacheItem>();
|
||||||
|
while (_addMessageXp.TryDequeue(out var usr))
|
||||||
|
toAddTo.Add(usr);
|
||||||
|
|
||||||
|
var group = toAddTo.GroupBy(x => (GuildId: x.Guild.Id, x.User));
|
||||||
|
if (toAddTo.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var toNotify =
|
foreach (var item in group)
|
||||||
new List<(IGuild Guild, IMessageChannel MessageChannel, IUser User, int Level,
|
|
||||||
XpNotificationLocation NotifyType, NotifOf NotifOf)>();
|
|
||||||
var roleRewards = new Dictionary<ulong, List<XpRoleReward>>();
|
|
||||||
var curRewards = new Dictionary<ulong, List<XpCurrencyReward>>();
|
|
||||||
|
|
||||||
var toAddTo = new List<UserCacheItem>();
|
|
||||||
while (_addMessageXp.TryDequeue(out var usr))
|
|
||||||
toAddTo.Add(usr);
|
|
||||||
|
|
||||||
var group = toAddTo.GroupBy(x => (GuildId: x.Guild.Id, x.User));
|
|
||||||
if (toAddTo.Count == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
await using (var uow = _db.GetDbContext())
|
|
||||||
{
|
{
|
||||||
foreach (var item in group)
|
var xp = item.Sum(x => x.XpAmount);
|
||||||
|
|
||||||
|
var usr = uow.GetOrCreateUserXpStats(item.Key.GuildId, item.Key.User.Id);
|
||||||
|
var du = uow.GetOrCreateUser(item.Key.User);
|
||||||
|
|
||||||
|
var globalXp = du.TotalXp;
|
||||||
|
var oldGlobalLevelData = new LevelStats(globalXp);
|
||||||
|
var newGlobalLevelData = new LevelStats(globalXp + xp);
|
||||||
|
|
||||||
|
var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||||
|
usr.Xp += xp;
|
||||||
|
du.TotalXp += xp;
|
||||||
|
if (du.Club is not null)
|
||||||
|
du.Club.Xp += xp;
|
||||||
|
var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||||
|
|
||||||
|
if (oldGlobalLevelData.Level < newGlobalLevelData.Level)
|
||||||
{
|
{
|
||||||
var xp = item.Sum(x => x.XpAmount);
|
du.LastLevelUp = DateTime.UtcNow;
|
||||||
|
var first = item.First();
|
||||||
var usr = uow.GetOrCreateUserXpStats(item.Key.GuildId, item.Key.User.Id);
|
if (du.NotifyOnLevelUp != XpNotificationLocation.None)
|
||||||
var du = uow.GetOrCreateUser(item.Key.User);
|
|
||||||
|
|
||||||
var globalXp = du.TotalXp;
|
|
||||||
var oldGlobalLevelData = new LevelStats(globalXp);
|
|
||||||
var newGlobalLevelData = new LevelStats(globalXp + xp);
|
|
||||||
|
|
||||||
var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
|
||||||
usr.Xp += xp;
|
|
||||||
du.TotalXp += xp;
|
|
||||||
if (du.Club is not null)
|
|
||||||
du.Club.Xp += xp;
|
|
||||||
var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
|
||||||
|
|
||||||
if (oldGlobalLevelData.Level < newGlobalLevelData.Level)
|
|
||||||
{
|
{
|
||||||
du.LastLevelUp = DateTime.UtcNow;
|
toNotify.Add((first.Guild, first.Channel, first.User, newGlobalLevelData.Level,
|
||||||
var first = item.First();
|
du.NotifyOnLevelUp, NotifOf.Global));
|
||||||
if (du.NotifyOnLevelUp != XpNotificationLocation.None)
|
|
||||||
{
|
|
||||||
toNotify.Add((first.Guild, first.Channel, first.User, newGlobalLevelData.Level,
|
|
||||||
du.NotifyOnLevelUp, NotifOf.Global));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldGuildLevelData.Level < newGuildLevelData.Level)
|
|
||||||
{
|
|
||||||
usr.LastLevelUp = DateTime.UtcNow;
|
|
||||||
//send level up notification
|
|
||||||
var first = item.First();
|
|
||||||
if (usr.NotifyOnLevelUp != XpNotificationLocation.None)
|
|
||||||
{
|
|
||||||
toNotify.Add((first.Guild, first.Channel, first.User, newGuildLevelData.Level,
|
|
||||||
usr.NotifyOnLevelUp, NotifOf.Server));
|
|
||||||
}
|
|
||||||
|
|
||||||
//give role
|
|
||||||
if (!roleRewards.TryGetValue(usr.GuildId, out var rrews))
|
|
||||||
{
|
|
||||||
rrews = uow.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
|
|
||||||
roleRewards.Add(usr.GuildId, rrews);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!curRewards.TryGetValue(usr.GuildId, out var crews))
|
|
||||||
{
|
|
||||||
crews = uow.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList();
|
|
||||||
curRewards.Add(usr.GuildId, crews);
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop through levels since last level up, so if a high amount of xp is gained, reward are still applied.
|
|
||||||
for (var i = oldGuildLevelData.Level + 1; i <= newGuildLevelData.Level; i++)
|
|
||||||
{
|
|
||||||
var rrew = rrews.FirstOrDefault(x => x.Level == i);
|
|
||||||
if (rrew is not null)
|
|
||||||
{
|
|
||||||
var role = first.User.Guild.GetRole(rrew.RoleId);
|
|
||||||
if (role is not null)
|
|
||||||
{
|
|
||||||
if (rrew.Remove)
|
|
||||||
_ = first.User.RemoveRoleAsync(role);
|
|
||||||
else
|
|
||||||
_ = first.User.AddRoleAsync(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get currency reward for this level
|
|
||||||
var crew = crews.FirstOrDefault(x => x.Level == i);
|
|
||||||
if (crew is not null)
|
|
||||||
//give the user the reward if it exists
|
|
||||||
await _cs.AddAsync(item.Key.User.Id, crew.Amount, new("xp", "level-up"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uow.SaveChanges();
|
if (oldGuildLevelData.Level < newGuildLevelData.Level)
|
||||||
|
{
|
||||||
|
usr.LastLevelUp = DateTime.UtcNow;
|
||||||
|
//send level up notification
|
||||||
|
var first = item.First();
|
||||||
|
if (usr.NotifyOnLevelUp != XpNotificationLocation.None)
|
||||||
|
{
|
||||||
|
toNotify.Add((first.Guild, first.Channel, first.User, newGuildLevelData.Level,
|
||||||
|
usr.NotifyOnLevelUp, NotifOf.Server));
|
||||||
|
}
|
||||||
|
|
||||||
|
//give role
|
||||||
|
if (!roleRewards.TryGetValue(usr.GuildId, out var rrews))
|
||||||
|
{
|
||||||
|
rrews = uow.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
|
||||||
|
roleRewards.Add(usr.GuildId, rrews);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curRewards.TryGetValue(usr.GuildId, out var crews))
|
||||||
|
{
|
||||||
|
crews = uow.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList();
|
||||||
|
curRewards.Add(usr.GuildId, crews);
|
||||||
|
}
|
||||||
|
|
||||||
|
//loop through levels since last level up, so if a high amount of xp is gained, reward are still applied.
|
||||||
|
for (var i = oldGuildLevelData.Level + 1; i <= newGuildLevelData.Level; i++)
|
||||||
|
{
|
||||||
|
var rrew = rrews.FirstOrDefault(x => x.Level == i);
|
||||||
|
if (rrew is not null)
|
||||||
|
{
|
||||||
|
var role = first.User.Guild.GetRole(rrew.RoleId);
|
||||||
|
if (role is not null)
|
||||||
|
{
|
||||||
|
if (rrew.Remove)
|
||||||
|
_ = first.User.RemoveRoleAsync(role);
|
||||||
|
else
|
||||||
|
_ = first.User.AddRoleAsync(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//get currency reward for this level
|
||||||
|
var crew = crews.FirstOrDefault(x => x.Level == i);
|
||||||
|
if (crew is not null)
|
||||||
|
//give the user the reward if it exists
|
||||||
|
await _cs.AddAsync(item.Key.User.Id, crew.Amount, new("xp", "level-up"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await toNotify.Select(async x =>
|
uow.SaveChanges();
|
||||||
{
|
}
|
||||||
if (x.NotifOf == NotifOf.Server)
|
|
||||||
{
|
|
||||||
if (x.NotifyType == XpNotificationLocation.Dm)
|
|
||||||
{
|
|
||||||
await x.User.SendConfirmAsync(_eb,
|
|
||||||
_strings.GetText(strs.level_up_dm(x.User.Mention,
|
|
||||||
Format.Bold(x.Level.ToString()),
|
|
||||||
Format.Bold(x.Guild.ToString() ?? "-")),
|
|
||||||
x.Guild.Id));
|
|
||||||
}
|
|
||||||
else if (x.MessageChannel is not null) // channel
|
|
||||||
{
|
|
||||||
await x.MessageChannel.SendConfirmAsync(_eb,
|
|
||||||
_strings.GetText(strs.level_up_channel(x.User.Mention,
|
|
||||||
Format.Bold(x.Level.ToString())),
|
|
||||||
x.Guild.Id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IMessageChannel chan;
|
|
||||||
if (x.NotifyType == XpNotificationLocation.Dm)
|
|
||||||
chan = await x.User.CreateDMChannelAsync();
|
|
||||||
else // channel
|
|
||||||
chan = x.MessageChannel;
|
|
||||||
|
|
||||||
await chan.SendConfirmAsync(_eb,
|
await toNotify.Select(async x =>
|
||||||
_strings.GetText(strs.level_up_global(x.User.Mention,
|
{
|
||||||
|
if (x.NotifOf == NotifOf.Server)
|
||||||
|
{
|
||||||
|
if (x.NotifyType == XpNotificationLocation.Dm)
|
||||||
|
{
|
||||||
|
await x.User.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_dm(x.User.Mention,
|
||||||
|
Format.Bold(x.Level.ToString()),
|
||||||
|
Format.Bold(x.Guild.ToString() ?? "-")),
|
||||||
|
x.Guild.Id));
|
||||||
|
}
|
||||||
|
else if (x.MessageChannel is not null) // channel
|
||||||
|
{
|
||||||
|
await x.MessageChannel.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_channel(x.User.Mention,
|
||||||
Format.Bold(x.Level.ToString())),
|
Format.Bold(x.Level.ToString())),
|
||||||
x.Guild.Id));
|
x.Guild.Id));
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.WhenAll();
|
else
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
IMessageChannel chan;
|
||||||
{
|
if (x.NotifyType == XpNotificationLocation.Dm)
|
||||||
Log.Error(ex, "Error In the XP update loop");
|
chan = await x.User.CreateDMChannelAsync();
|
||||||
}
|
else // channel
|
||||||
|
chan = x.MessageChannel;
|
||||||
|
|
||||||
|
await chan.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_global(x.User.Mention,
|
||||||
|
Format.Bold(x.Level.ToString())),
|
||||||
|
x.Guild.Id));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.WhenAll();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error In the XP update loop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,12 +35,6 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Html2Markdown" Version="5.0.2.561" />
|
<PackageReference Include="Html2Markdown" Version="5.0.2.561" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
@@ -59,10 +53,22 @@
|
|||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.2.88" />
|
<PackageReference Include="StackExchange.Redis" Version="2.2.88" />
|
||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||||
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.6.1" />
|
|
||||||
<PackageReference Include="Humanizer" Version="2.14.1" />
|
<PackageReference Include="Humanizer" Version="2.14.1" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" />
|
||||||
|
|
||||||
|
<!-- Db-related packages -->
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
|
||||||
|
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.6.1" />
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
|
||||||
|
|
||||||
<!-- Remove this when static abstract interface members support is released -->
|
<!-- Remove this when static abstract interface members support is released -->
|
||||||
<PackageReference Include="System.Runtime.Experimental" Version="6.0.0" />
|
<PackageReference Include="System.Runtime.Experimental" Version="6.0.0" />
|
||||||
|
|
||||||
@@ -105,6 +111,9 @@
|
|||||||
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
||||||
<DefineConstants>$(DefineConstants);GLOBAL_NADEKO</DefineConstants>
|
<DefineConstants>$(DefineConstants);GLOBAL_NADEKO</DefineConstants>
|
||||||
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>portable</DebugType>
|
||||||
|
<DebugSymbols>false</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- TODO: Remove this when the conflict issue in System.Runtime.Experimental is fixed -->
|
<!-- TODO: Remove this when the conflict issue in System.Runtime.Experimental is fixed -->
|
||||||
|
Reference in New Issue
Block a user