wip reimplementation of the voicexp
This commit is contained in:
parent
5d9326b65e
commit
dbc312dd9d
2 changed files with 61 additions and 131 deletions
src/EllieBot
|
@ -154,7 +154,7 @@
|
|||
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalEllie' ">
|
||||
<!-- Define trace doesn't seem to affect the build at all so I had to remove $(DefineConstants)-->
|
||||
<DefineTrace>false</DefineTrace>
|
||||
<DefineConstants>GLOBAL_NADEKO</DefineConstants>
|
||||
<DefineConstants>GLOBAL_ELLIE</DefineConstants>
|
||||
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>portable</DebugType>
|
||||
|
|
|
@ -140,6 +140,22 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
|
||||
return;
|
||||
|
||||
async Task VoiceUpdateTimer()
|
||||
{
|
||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||
while (await timer.WaitForNextTickAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
await UpdateVoiceXp();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Error updating voice xp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task UpdateTimer()
|
||||
{
|
||||
// todo a bigger loop that runs once every XpTimer
|
||||
|
@ -164,17 +180,46 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
/// </summary>
|
||||
private readonly ConcurrentHashSet<IGuildUser> _usersBatch = new();
|
||||
|
||||
private readonly ConcurrentHashSet<IGuildUser> _voiceXPBatch = new();
|
||||
|
||||
private async Task UpdateVoiceXp()
|
||||
{
|
||||
var xpAmount = (int)_xpConfig.Data.VoiceXpPerMinute;
|
||||
var oldBatch = _voiceXPBatch.ToArray();
|
||||
_voiceXPBatch.Clear();
|
||||
var validUsers = new HashSet<IGuildUser>();
|
||||
|
||||
var guilds = _client.Guilds;
|
||||
|
||||
foreach (var g in guilds)
|
||||
foreach (var vc in g.VoiceChannels)
|
||||
foreach (var u in vc.ConnectedUsers)
|
||||
if (!u.IsMuted && !u.IsDeafened
|
||||
&& vc.ConnectedUsers.Count(x => !x.IsBot) > 1)
|
||||
{
|
||||
if (oldBatch.Contains(u))
|
||||
validUsers.Add(u);
|
||||
|
||||
_voiceXPBatch.Add(u);
|
||||
}
|
||||
|
||||
await UpdateXpInternalAsync(validUsers.DistinctBy(x => x.Id).ToArray(), xpAmount);
|
||||
}
|
||||
|
||||
private async Task UpdateXp()
|
||||
{
|
||||
var xpAmount = _xpConfig.Data.XpPerMessage;
|
||||
var currentBatch = _usersBatch.ToArray();
|
||||
_usersBatch.Clear();
|
||||
|
||||
await UpdateXpInternalAsync(currentBatch, xpAmount);
|
||||
}
|
||||
|
||||
private async Task UpdateXpInternalAsync(IGuildUser[] currentBatch, int xpAmount)
|
||||
{
|
||||
if (currentBatch.Length == 0)
|
||||
return;
|
||||
|
||||
var ids = currentBatch.Select(x => x.Id).ToArray();
|
||||
|
||||
await using var ctx = _db.GetDbContext();
|
||||
await using var lctx = ctx.CreateLinqToDBConnection();
|
||||
|
||||
|
@ -492,7 +537,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
});
|
||||
}
|
||||
|
||||
uow.SaveChanges();
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyCollection<UserXpStats>> GetGuildUserXps(ulong guildId, int page)
|
||||
|
@ -552,29 +597,16 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task Client_OnUserVoiceStateUpdated(SocketUser socketUser, SocketVoiceState before, SocketVoiceState after)
|
||||
private async Task Client_OnUserVoiceStateUpdated(SocketUser socketUser, SocketVoiceState before,
|
||||
SocketVoiceState after)
|
||||
{
|
||||
if (socketUser is not SocketGuildUser user || user.IsBot)
|
||||
return Task.CompletedTask;
|
||||
return;
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
if (after.VoiceChannel is not null)
|
||||
{
|
||||
if (before.VoiceChannel is not null)
|
||||
await ScanChannelForVoiceXp(before.VoiceChannel);
|
||||
|
||||
if (after.VoiceChannel is not null && after.VoiceChannel != before.VoiceChannel)
|
||||
{
|
||||
await ScanChannelForVoiceXp(after.VoiceChannel);
|
||||
}
|
||||
else if (after.VoiceChannel is null && before.VoiceChannel is not null)
|
||||
{
|
||||
// In this case, the user left the channel and the previous for loops didn't catch
|
||||
// it because it wasn't in any new channel. So we need to get rid of it.
|
||||
await UserLeftVoiceChannel(user, before.VoiceChannel);
|
||||
}
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
await ScanChannelForVoiceXp(after.VoiceChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ScanChannelForVoiceXp(SocketVoiceChannel channel)
|
||||
|
@ -582,27 +614,13 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
if (ShouldTrackVoiceChannel(channel))
|
||||
{
|
||||
foreach (var user in channel.ConnectedUsers)
|
||||
await ScanUserForVoiceXp(user, channel);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var user in channel.ConnectedUsers)
|
||||
await UserLeftVoiceChannel(user, channel);
|
||||
{
|
||||
if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel))
|
||||
await UserJoinedVoiceChannel(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assumes that the channel itself is valid and adding xp.
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="channel"></param>
|
||||
private async Task ScanUserForVoiceXp(SocketGuildUser user, SocketVoiceChannel channel)
|
||||
{
|
||||
if (UserParticipatingInVoiceChannel(user) && ShouldTrackXp(user, channel))
|
||||
await UserJoinedVoiceChannel(user);
|
||||
else
|
||||
await UserLeftVoiceChannel(user, channel);
|
||||
}
|
||||
|
||||
private bool ShouldTrackVoiceChannel(SocketVoiceChannel channel)
|
||||
=> channel.ConnectedUsers.Where(UserParticipatingInVoiceChannel).Take(2).Count() >= 2;
|
||||
|
@ -619,84 +637,10 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
|
||||
await _c.AddAsync(GetVoiceXpKey(user.Id),
|
||||
value,
|
||||
TimeSpan.FromMinutes(_xpConfig.Data.VoiceMaxMinutes),
|
||||
overwrite: false);
|
||||
TimeSpan.FromMinutes(1),
|
||||
overwrite: true);
|
||||
}
|
||||
|
||||
// private void UserJoinedVoiceChannel(SocketGuildUser user)
|
||||
// {
|
||||
// var key = $"{_creds.RedisKey()}_user_xp_vc_join_{user.Id}";
|
||||
// var value = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
//
|
||||
// _cache.Redis.GetDatabase()
|
||||
// .StringSet(key,
|
||||
// value,
|
||||
// TimeSpan.FromMinutes(_xpConfig.Data.VoiceMaxMinutes),
|
||||
// when: When.NotExists);
|
||||
// }
|
||||
|
||||
private async Task UserLeftVoiceChannel(SocketGuildUser user, SocketVoiceChannel channel)
|
||||
{
|
||||
var key = GetVoiceXpKey(user.Id);
|
||||
var result = await _c.GetAsync(key);
|
||||
if (!await _c.RemoveAsync(key))
|
||||
return;
|
||||
|
||||
// Allow for if this function gets called multiple times when a user leaves a channel.
|
||||
if (!result.TryGetValue(out var unixTime))
|
||||
return;
|
||||
|
||||
var dateStart = DateTimeOffset.FromUnixTimeSeconds(unixTime);
|
||||
var dateEnd = DateTimeOffset.UtcNow;
|
||||
var minutes = (dateEnd - dateStart).TotalMinutes;
|
||||
var xp = _xpConfig.Data.VoiceXpPerMinute * minutes;
|
||||
var actualXp = (int)Math.Floor(xp);
|
||||
|
||||
if (actualXp > 0)
|
||||
{
|
||||
Log.Information("Adding {Amount} voice xp to {User}", actualXp, user.ToString());
|
||||
await _xpGainQueue.Writer.WriteAsync(new()
|
||||
{
|
||||
Guild = channel.Guild,
|
||||
User = user,
|
||||
XpAmount = actualXp,
|
||||
Channel = channel
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* private void UserLeftVoiceChannel(SocketGuildUser user, SocketVoiceChannel channel)
|
||||
{
|
||||
var key = $"{_creds.RedisKey()}_user_xp_vc_join_{user.Id}";
|
||||
var value = _cache.Redis.GetDatabase().StringGet(key);
|
||||
_cache.Redis.GetDatabase().KeyDelete(key);
|
||||
|
||||
// Allow for if this function gets called multiple times when a user leaves a channel.
|
||||
if (value.IsNull)
|
||||
return;
|
||||
|
||||
if (!value.TryParse(out long startUnixTime))
|
||||
return;
|
||||
|
||||
var dateStart = DateTimeOffset.FromUnixTimeSeconds(startUnixTime);
|
||||
var dateEnd = DateTimeOffset.UtcNow;
|
||||
var minutes = (dateEnd - dateStart).TotalMinutes;
|
||||
var xp = _xpConfig.Data.VoiceXpPerMinute * minutes;
|
||||
var actualXp = (int)Math.Floor(xp);
|
||||
|
||||
if (actualXp > 0)
|
||||
{
|
||||
_addMessageXp.Enqueue(new()
|
||||
{
|
||||
Guild = channel.Guild,
|
||||
User = user,
|
||||
XpAmount = actualXp
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private bool ShouldTrackXp(SocketGuildUser user, IMessageChannel channel)
|
||||
{
|
||||
var channelId = channel.Id;
|
||||
|
@ -744,20 +688,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// public void AddXpDirectly(IGuildUser user, IMessageChannel channel, int amount)
|
||||
// {
|
||||
// if (amount <= 0)
|
||||
// throw new ArgumentOutOfRangeException(nameof(amount));
|
||||
//
|
||||
// _xpGainQueue.Writer.WriteAsync(new()
|
||||
// {
|
||||
// Guild = user.Guild,
|
||||
// Channel = channel,
|
||||
// User = user,
|
||||
// XpAmount = amount
|
||||
// });
|
||||
// }
|
||||
|
||||
public async Task<int> AddXpToUsersAsync(ulong guildId, long amount, params ulong[] userIds)
|
||||
{
|
||||
await using var ctx = _db.GetDbContext();
|
||||
|
|
Loading…
Add table
Reference in a new issue