Rewrite VoiceRoleSync
Implement a slightly more sane configuration
This commit is contained in:
parent
2d4ae0b4a8
commit
0ef78a53dc
2 changed files with 30 additions and 26 deletions
|
@ -1,32 +1,36 @@
|
||||||
|
using RegexBot.Common;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace RegexBot.Modules.VoiceRoleSync;
|
namespace RegexBot.Modules.VoiceRoleSync;
|
||||||
/// <summary>
|
|
||||||
/// Dictionary wrapper. Key = voice channel ID, Value = role.
|
|
||||||
/// </summary>
|
|
||||||
class ModuleConfig {
|
class ModuleConfig {
|
||||||
|
/// <summary>
|
||||||
|
/// Key = voice channel ID, Value = role ID.
|
||||||
|
/// </summary>
|
||||||
private readonly ReadOnlyDictionary<ulong, ulong> _values;
|
private readonly ReadOnlyDictionary<ulong, ulong> _values;
|
||||||
|
|
||||||
public int Count { get => _values.Count; }
|
public int Count { get => _values.Count; }
|
||||||
|
|
||||||
public ModuleConfig(JObject config) {
|
public ModuleConfig(JObject config, SocketGuild g) {
|
||||||
// Configuration format is expected to be an object that contains other objects.
|
// Configuration: Object with properties.
|
||||||
// The objects themselves should have their name be the voice channel,
|
// Property name is a role entity name
|
||||||
// and the value be the role to be applied.
|
// Value is a string or array of voice channel IDs.
|
||||||
|
|
||||||
// TODO Make it accept names; currently only accepts ulongs
|
|
||||||
|
|
||||||
var values = new Dictionary<ulong, ulong>();
|
var values = new Dictionary<ulong, ulong>();
|
||||||
|
|
||||||
foreach (var item in config.Properties()) {
|
foreach (var item in config.Properties()) {
|
||||||
if (!ulong.TryParse(item.Name, out var voice)) throw new ModuleLoadException($"{item.Name} is not a voice channel ID.");
|
var name = new EntityName(item.Name);
|
||||||
var valstr = item.Value.Value<string>();
|
if (name.Type != EntityType.Role) throw new ModuleLoadException($"'{item.Name}' is not specified as a role.");
|
||||||
if (!ulong.TryParse(valstr, out var role)) throw new ModuleLoadException($"{valstr} is not a role ID.");
|
var role = name.FindRoleIn(g);
|
||||||
|
if (role == null) throw new ModuleLoadException($"Unable to find role '{name}'.");
|
||||||
|
|
||||||
values[voice] = role;
|
var channels = Utilities.LoadStringOrStringArray(item.Value);
|
||||||
|
if (channels.Count == 0) throw new ModuleLoadException($"One or more channels must be defined under '{name}'.");
|
||||||
|
foreach (var id in channels) {
|
||||||
|
if (!ulong.TryParse(id, out var channelId)) throw new ModuleLoadException("Voice channel IDs must be numeric.");
|
||||||
|
if (values.ContainsKey(channelId)) throw new ModuleLoadException($"'{channelId}' cannot be specified more than once.");
|
||||||
|
values.Add(channelId, role.Id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_values = new ReadOnlyDictionary<ulong, ulong>(values);
|
_values = new(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SocketRole? GetAssociatedRoleFor(SocketVoiceChannel voiceChannel) {
|
public SocketRole? GetAssociatedRoleFor(SocketVoiceChannel voiceChannel) {
|
||||||
|
@ -36,8 +40,9 @@ class ModuleConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<SocketRole> GetTrackedRoles(SocketGuild guild) {
|
public IEnumerable<SocketRole> GetTrackedRoles(SocketGuild guild) {
|
||||||
foreach (var pair in _values) {
|
var roles = _values.Select(v => v.Value).Distinct();
|
||||||
var r = guild.GetRole(pair.Value);
|
foreach (var id in roles) {
|
||||||
|
var r = guild.GetRole(id);
|
||||||
if (r != null) yield return r;
|
if (r != null) yield return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ namespace RegexBot.Modules.VoiceRoleSync;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegexbotModule]
|
[RegexbotModule]
|
||||||
internal class VoiceRoleSync : RegexbotModule {
|
internal class VoiceRoleSync : RegexbotModule {
|
||||||
// TODO wishlist? specify multiple definitions - multiple channels associated with multiple roles.
|
|
||||||
|
|
||||||
public VoiceRoleSync(RegexbotClient bot) : base(bot) {
|
public VoiceRoleSync(RegexbotClient bot) : base(bot) {
|
||||||
DiscordClient.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
DiscordClient.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +16,8 @@ internal class VoiceRoleSync : RegexbotModule {
|
||||||
if (settings == null) return; // not enabled here
|
if (settings == null) return; // not enabled here
|
||||||
|
|
||||||
async Task RemoveAllAssociatedRoles()
|
async Task RemoveAllAssociatedRoles()
|
||||||
=> await user.RemoveRolesAsync(settings.GetTrackedRoles(user.Guild).Intersect(user.Roles));
|
=> await user.RemoveRolesAsync(settings.GetTrackedRoles(user.Guild).Intersect(user.Roles),
|
||||||
|
new Discord.RequestOptions() { AuditLogReason = nameof(VoiceRoleSync) + ": No longer in associated voice channel." });
|
||||||
|
|
||||||
if (after.VoiceChannel == null) {
|
if (after.VoiceChannel == null) {
|
||||||
// Not in any voice channel. Remove all roles being tracked by this instance. Clear.
|
// Not in any voice channel. Remove all roles being tracked by this instance. Clear.
|
||||||
|
@ -35,10 +34,10 @@ internal class VoiceRoleSync : RegexbotModule {
|
||||||
await RemoveAllAssociatedRoles();
|
await RemoveAllAssociatedRoles();
|
||||||
} else {
|
} else {
|
||||||
// In a tracked voice channel: Clear all except target, add target if needed.
|
// In a tracked voice channel: Clear all except target, add target if needed.
|
||||||
await user.RemoveRolesAsync(settings.GetTrackedRoles(user.Guild)
|
var toRemove = settings.GetTrackedRoles(user.Guild).Where(role => role.Id != targetRole.Id).Intersect(user.Roles);
|
||||||
.Where(role => role.Id != targetRole.Id)
|
if (toRemove.Any()) await user.RemoveRolesAsync(toRemove);
|
||||||
.Intersect(user.Roles));
|
if (!user.Roles.Contains(targetRole)) await user.AddRoleAsync(targetRole,
|
||||||
if (!user.Roles.Contains(targetRole)) await user.AddRoleAsync(targetRole);
|
new Discord.RequestOptions() { AuditLogReason = nameof(VoiceRoleSync) + ": Joined associated voice channel." });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +48,7 @@ internal class VoiceRoleSync : RegexbotModule {
|
||||||
if (config.Type != JTokenType.Object)
|
if (config.Type != JTokenType.Object)
|
||||||
throw new ModuleLoadException("Configuration for this section is invalid.");
|
throw new ModuleLoadException("Configuration for this section is invalid.");
|
||||||
|
|
||||||
var newconf = new ModuleConfig((JObject)config);
|
var newconf = new ModuleConfig((JObject)config, Bot.DiscordClient.GetGuild(guildID));
|
||||||
Log(DiscordClient.GetGuild(guildID), $"Configured with {newconf.Count} pairing(s).");
|
Log(DiscordClient.GetGuild(guildID), $"Configured with {newconf.Count} pairing(s).");
|
||||||
return Task.FromResult<object?>(newconf);
|
return Task.FromResult<object?>(newconf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue