diff --git a/Plugins/Mute/Commands/MuteCommand.cs b/Plugins/Mute/Commands/MuteCommand.cs
index 82c4cd7e2..0e894f542 100644
--- a/Plugins/Mute/Commands/MuteCommand.cs
+++ b/Plugins/Mute/Commands/MuteCommand.cs
@@ -20,8 +20,8 @@ public MuteCommand(CommandConfiguration config, ITranslationLookup translationLo
Permission = EFClient.Permission.Moderator;
RequiresTarget = true;
SupportedGames = Plugin.SupportedGames;
- Arguments = new[]
- {
+ Arguments =
+ [
new CommandArgument
{
Name = translationLookup["COMMANDS_ARGS_PLAYER"],
@@ -32,7 +32,7 @@ public MuteCommand(CommandConfiguration config, ITranslationLookup translationLo
Name = translationLookup["COMMANDS_ARGS_REASON"],
Required = true
}
- };
+ ];
}
public override async Task ExecuteAsync(GameEvent gameEvent)
diff --git a/Plugins/Mute/Commands/MuteInfoCommand.cs b/Plugins/Mute/Commands/MuteInfoCommand.cs
index 4622a0ce9..bba01a9e7 100644
--- a/Plugins/Mute/Commands/MuteInfoCommand.cs
+++ b/Plugins/Mute/Commands/MuteInfoCommand.cs
@@ -21,14 +21,14 @@ public MuteInfoCommand(CommandConfiguration config, ITranslationLookup translati
Permission = EFClient.Permission.Moderator;
RequiresTarget = true;
SupportedGames = Plugin.SupportedGames;
- Arguments = new[]
- {
+ Arguments =
+ [
new CommandArgument
{
Name = translationLookup["COMMANDS_ARGS_PLAYER"],
Required = true
}
- };
+ ];
}
public override async Task ExecuteAsync(GameEvent gameEvent)
diff --git a/Plugins/Mute/Commands/TempMuteCommand.cs b/Plugins/Mute/Commands/TempMuteCommand.cs
index 69a2999c9..9275b1075 100644
--- a/Plugins/Mute/Commands/TempMuteCommand.cs
+++ b/Plugins/Mute/Commands/TempMuteCommand.cs
@@ -7,10 +7,9 @@
namespace IW4MAdmin.Plugins.Mute.Commands;
-public class TempMuteCommand : Command
+public partial class TempMuteCommand : Command
{
private readonly MuteManager _muteManager;
- private const string TempBanRegex = @"([0-9]+\w+)\ (.+)";
public TempMuteCommand(CommandConfiguration config, ITranslationLookup translationLookup, MuteManager muteManager) : base(config,
translationLookup)
@@ -22,8 +21,8 @@ public TempMuteCommand(CommandConfiguration config, ITranslationLookup translati
Permission = EFClient.Permission.Moderator;
RequiresTarget = true;
SupportedGames = Plugin.SupportedGames;
- Arguments = new[]
- {
+ Arguments =
+ [
new CommandArgument
{
Name = translationLookup["COMMANDS_ARGS_PLAYER"],
@@ -39,7 +38,7 @@ public TempMuteCommand(CommandConfiguration config, ITranslationLookup translati
Name = translationLookup["COMMANDS_ARGS_REASON"],
Required = true
}
- };
+ ];
}
public override async Task ExecuteAsync(GameEvent gameEvent)
@@ -49,8 +48,8 @@ public override async Task ExecuteAsync(GameEvent gameEvent)
gameEvent.Origin.Tell(_translationLookup["COMMANDS_DENY_SELF_TARGET"]);
return;
}
-
- var match = Regex.Match(gameEvent.Data, TempBanRegex);
+
+ var match = TempBanRegex().Match(gameEvent.Data);
if (match.Success)
{
var expiration = DateTime.UtcNow + match.Groups[1].ToString().ParseTimespan();
@@ -72,4 +71,7 @@ public override async Task ExecuteAsync(GameEvent gameEvent)
gameEvent.Origin.Tell(_translationLookup["PLUGINS_MUTE_COMMANDS_TEMPMUTE_BAD_FORMAT"]);
}
+
+ [GeneratedRegex(@"([0-9]+\w+)\ (.+)")]
+ private static partial Regex TempBanRegex();
}
diff --git a/Plugins/Mute/Commands/UnmuteCommand.cs b/Plugins/Mute/Commands/UnmuteCommand.cs
index e59c4334a..043611442 100644
--- a/Plugins/Mute/Commands/UnmuteCommand.cs
+++ b/Plugins/Mute/Commands/UnmuteCommand.cs
@@ -20,8 +20,8 @@ public UnmuteCommand(CommandConfiguration config, ITranslationLookup translation
Permission = EFClient.Permission.Moderator;
RequiresTarget = true;
SupportedGames = Plugin.SupportedGames;
- Arguments = new[]
- {
+ Arguments =
+ [
new CommandArgument
{
Name = translationLookup["COMMANDS_ARGS_PLAYER"],
@@ -32,7 +32,7 @@ public UnmuteCommand(CommandConfiguration config, ITranslationLookup translation
Name = translationLookup["COMMANDS_ARGS_REASON"],
Required = true
}
- };
+ ];
}
public override async Task ExecuteAsync(GameEvent gameEvent)
diff --git a/Plugins/Mute/Mute.csproj b/Plugins/Mute/Mute.csproj
index a227b7fed..3341c5258 100644
--- a/Plugins/Mute/Mute.csproj
+++ b/Plugins/Mute/Mute.csproj
@@ -8,6 +8,7 @@
Library
Debug;Release;Prerelease
AnyCPU
+ IW4MAdmin.Plugins.Mute
diff --git a/Plugins/Mute/MuteManager.cs b/Plugins/Mute/MuteManager.cs
index 537465b12..e758d5eb9 100644
--- a/Plugins/Mute/MuteManager.cs
+++ b/Plugins/Mute/MuteManager.cs
@@ -10,23 +10,15 @@
namespace IW4MAdmin.Plugins.Mute;
-public class MuteManager
+public class MuteManager(
+ ILogger logger,
+ IDatabaseContextFactory databaseContextFactory,
+ IMetaServiceV2 metaService,
+ ITranslationLookup translationLookup)
{
- private readonly IMetaServiceV2 _metaService;
- private readonly ITranslationLookup _translationLookup;
- private readonly ILogger _logger;
- private readonly IDatabaseContextFactory _databaseContextFactory;
+ private readonly ILogger _logger = logger;
private readonly SemaphoreSlim _onMuteAction = new(1, 1);
- public MuteManager(ILogger logger, IDatabaseContextFactory databaseContextFactory,
- IMetaServiceV2 metaService, ITranslationLookup translationLookup)
- {
- _logger = logger;
- _databaseContextFactory = databaseContextFactory;
- _metaService = metaService;
- _translationLookup = translationLookup;
- }
-
public static bool IsExpiredMute(MuteStateMeta muteStateMeta) =>
muteStateMeta.Expiration is not null && muteStateMeta.Expiration < DateTime.UtcNow;
@@ -42,7 +34,7 @@ public async Task GetCurrentMuteState(EFClient client)
var muteState = await ReadPersistentDataV1(client);
clientMuteMeta = new MuteStateMeta
{
- Reason = muteState is null ? string.Empty : _translationLookup["PLUGINS_MUTE_MIGRATED"],
+ Reason = muteState is null ? string.Empty : translationLookup["PLUGINS_MUTE_MIGRATED"],
Expiration = muteState switch
{
null => DateTime.UtcNow,
@@ -149,7 +141,7 @@ private async Task CreatePenalty(MuteState muteState, EFClient origin, EFClient
private async Task ExpireMutePenalties(EFClient client)
{
- await using var context = _databaseContextFactory.CreateContext();
+ await using var context = databaseContextFactory.CreateContext();
var mutePenalties = await context.Penalties
.Where(penalty => penalty.OffenderId == client.ClientId)
.Where(penalty => penalty.Type == EFPenalty.PenaltyType.Mute || penalty.Type == EFPenalty.PenaltyType.TempMute)
@@ -184,7 +176,7 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut
}
private async Task ReadPersistentDataV1(EFClient client) => TryParse(
- (await _metaService.GetPersistentMeta(Plugin.MuteKey, client.ClientId))?.Value, out var muteState)
+ (await metaService.GetPersistentMeta(Plugin.MuteKey, client.ClientId))?.Value, out var muteState)
? muteState
: null;
@@ -195,7 +187,7 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut
if (clientMuteMeta is not null) return clientMuteMeta;
// Get meta from database and store in client if exists
- clientMuteMeta = await _metaService.GetPersistentMetaValue(Plugin.MuteKey, client.ClientId);
+ clientMuteMeta = await metaService.GetPersistentMetaValue(Plugin.MuteKey, client.ClientId);
if (clientMuteMeta is not null) client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta);
return clientMuteMeta;
@@ -204,6 +196,6 @@ public static async Task PerformGameCommand(Server server, EFClient? client, Mut
private async Task WritePersistentData(EFClient client, MuteStateMeta clientMuteMeta)
{
client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta);
- await _metaService.SetPersistentMetaValue(Plugin.MuteKey, clientMuteMeta, client.ClientId);
+ await metaService.SetPersistentMetaValue(Plugin.MuteKey, clientMuteMeta, client.ClientId);
}
}
diff --git a/Plugins/Mute/Plugin.cs b/Plugins/Mute/Plugin.cs
index d1c36815a..44ca8b2cd 100644
--- a/Plugins/Mute/Plugin.cs
+++ b/Plugins/Mute/Plugin.cs
@@ -21,15 +21,14 @@ public class Plugin : IPluginV2
public const string MuteKey = "IW4MMute";
public static IManager Manager { get; private set; } = null!;
- public static Server.Game[] SupportedGames { get; private set; } = Array.Empty();
+ public static Server.Game[] SupportedGames { get; private set; } = [];
private static readonly string[] DisabledCommands = [nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"];
private readonly IInteractionRegistration _interactionRegistration;
private readonly IRemoteCommandService _remoteCommandService;
private readonly MuteManager _muteManager;
private const string MuteInteraction = "Webfront::Profile::Mute";
- public Plugin(IInteractionRegistration interactionRegistration,
- IRemoteCommandService remoteCommandService, MuteManager muteManager)
+ public Plugin(IInteractionRegistration interactionRegistration, IRemoteCommandService remoteCommandService, MuteManager muteManager)
{
_interactionRegistration = interactionRegistration;
_remoteCommandService = remoteCommandService;
@@ -37,7 +36,6 @@ public Plugin(IInteractionRegistration interactionRegistration,
IManagementEventSubscriptions.Load += OnLoad;
IManagementEventSubscriptions.Unload += OnUnload;
-
IManagementEventSubscriptions.ClientStateInitialized += OnClientStateInitialized;
IGameServerEventSubscriptions.ClientDataUpdated += OnClientDataUpdated;
@@ -73,7 +71,7 @@ private Task OnLoad(IManager manager, CancellationToken cancellationToken)
return !DisabledCommands.Contains(command.GetType().Name) && !command.IsBroadcast;
});
- _interactionRegistration.RegisterInteraction(MuteInteraction, async (targetClientId, game, token) =>
+ _interactionRegistration.RegisterInteraction(MuteInteraction, async (targetClientId, game, _) =>
{
if (!targetClientId.HasValue || game.HasValue && !SupportedGames.Contains((Server.Game)game.Value))
{
@@ -81,16 +79,16 @@ private Task OnLoad(IManager manager, CancellationToken cancellationToken)
}
var clientMuteMetaState =
- (await _muteManager.GetCurrentMuteState(new EFClient {ClientId = targetClientId.Value}))
+ (await _muteManager.GetCurrentMuteState(new EFClient { ClientId = targetClientId.Value }))
.MuteState;
var server = manager.GetServers().First();
- string GetCommandName(Type commandType) =>
- manager.Commands.FirstOrDefault(command => command.GetType() == commandType)?.Name ?? "";
-
return clientMuteMetaState is MuteState.Unmuted or MuteState.Unmuting
? CreateMuteInteraction(targetClientId.Value, server, GetCommandName)
: CreateUnmuteInteraction(targetClientId.Value, server, GetCommandName);
+
+ string GetCommandName(Type commandType) =>
+ manager.Commands.FirstOrDefault(command => command.GetType() == commandType)?.Name ?? string.Empty;
});
return Task.CompletedTask;
}
@@ -109,9 +107,9 @@ private async Task OnClientDataUpdated(ClientDataUpdateEvent updateEvent, Cancel
}
var networkIds = updateEvent.Clients.Select(client => client.NetworkId).ToList();
- var ingameClients = updateEvent.Server.ConnectedClients.Where(client => networkIds.Contains(client.NetworkId));
+ var inGameClients = updateEvent.Server.ConnectedClients.Where(client => networkIds.Contains(client.NetworkId));
- await Task.WhenAll(ingameClients.Select(async client =>
+ await Task.WhenAll(inGameClients.Select(async client =>
{
var muteMetaUpdate = await _muteManager.GetCurrentMuteState(client);
if (!muteMetaUpdate.CommandExecuted)
@@ -137,7 +135,7 @@ private async Task OnClientMessaged(ClientMessageEvent messageEvent, Cancellatio
{
var muteMetaSay = await _muteManager.GetCurrentMuteState(messageEvent.Origin);
- if (muteMetaSay.MuteState == MuteState.Muted)
+ if (muteMetaSay.MuteState is MuteState.Muted)
{
// Let the client know when their mute expires.
messageEvent.Origin.Tell(Utilities.CurrentLocalization
@@ -160,16 +158,16 @@ private async Task OnClientStateInitialized(ClientStateInitializeEvent state, Ca
switch (muteMetaJoin)
{
- case {MuteState: MuteState.Muted}:
+ case { MuteState: MuteState.Muted }:
// Let the client know when their mute expires.
state.Client.Tell(Utilities.CurrentLocalization
.LocalizationIndex["PLUGINS_MUTE_REMAINING_TIME"].FormatExt(
- muteMetaJoin is {Expiration: not null}
+ muteMetaJoin is { Expiration: not null }
? muteMetaJoin.Expiration.Value.HumanizeForCurrentCulture()
: Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_NEVER"],
muteMetaJoin.Reason));
break;
- case {MuteState: MuteState.Unmuting}:
+ case { MuteState: MuteState.Unmuting }:
// Handle unmute of unmuted players.
await _muteManager.Unmute(state.Client.CurrentServer, Utilities.IW4MAdminClient(), state.Client,
muteMetaJoin.Reason ?? string.Empty);
@@ -191,6 +189,29 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server,
Values = (Dictionary?)null
};
+ var presetReasonInput = new
+ {
+ Name = "PresetReason",
+ Label = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_LABEL_PRESET_REASON"],
+ Type = "select",
+ Values = (Dictionary?)new Dictionary
+ {
+ { string.Empty, string.Empty },
+ {
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_ABUSIVE"],
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_ABUSIVE"]
+ },
+ {
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_SPAMMING"],
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_SPAMMING"]
+ },
+ {
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_OTHER"],
+ Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_MUTE_REASON_OTHER"]
+ }
+ }
+ };
+
var durationInput = new
{
Name = "Duration",
@@ -198,16 +219,16 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server,
Type = "select",
Values = (Dictionary?)new Dictionary
{
- {"5m", TimeSpan.FromMinutes(5).HumanizeForCurrentCulture()},
- {"30m", TimeSpan.FromMinutes(30).HumanizeForCurrentCulture()},
- {"1h", TimeSpan.FromHours(1).HumanizeForCurrentCulture()},
- {"6h", TimeSpan.FromHours(6).HumanizeForCurrentCulture()},
- {"1d", TimeSpan.FromDays(1).HumanizeForCurrentCulture()},
- {"p", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_SELECTION_PERMANENT"]}
+ { "5m", TimeSpan.FromMinutes(5).HumanizeForCurrentCulture() },
+ { "30m", TimeSpan.FromMinutes(30).HumanizeForCurrentCulture() },
+ { "1h", TimeSpan.FromHours(1).HumanizeForCurrentCulture() },
+ { "6h", TimeSpan.FromHours(6).HumanizeForCurrentCulture() },
+ { "1d", TimeSpan.FromDays(1).HumanizeForCurrentCulture() },
+ { "p", Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_ACTION_SELECTION_PERMANENT"] }
}
};
- var inputs = new[] {reasonInput, durationInput};
+ var inputs = new[] { reasonInput, presetReasonInput, durationInput };
var inputsJson = JsonSerializer.Serialize(inputs);
return new InteractionData
@@ -216,10 +237,10 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server,
Name = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"],
DisplayMeta = "oi-volume-off",
ActionPath = "DynamicAction",
- ActionMeta = new()
+ ActionMeta = new Dictionary
{
- {"InteractionId", MuteInteraction},
- {"Inputs", inputsJson},
+ { "InteractionId", MuteInteraction },
+ { "Inputs", inputsJson },
{
"ActionButtonLabel",
Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"]
@@ -228,7 +249,7 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server,
"Name",
Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MUTE"]
},
- {"ShouldRefresh", true.ToString()}
+ { "ShouldRefresh", true.ToString() }
},
MinimumPermission = Data.Models.Client.EFClient.Permission.Moderator,
Source = Name,
@@ -250,11 +271,14 @@ private InteractionData CreateMuteInteraction(int targetClientId, Server server,
args.Add(duration);
}
- if (meta.TryGetValue(reasonInput.Name, out var reason))
+ var definedReason = meta.TryGetValue(reasonInput.Name, out var reason) ? reason : string.Empty;
+ if (meta.TryGetValue(presetReasonInput.Name, out var presetReason) && string.IsNullOrWhiteSpace(definedReason))
{
- args.Add(reason);
+ definedReason = presetReason;
}
+ args.Add(definedReason);
+
var commandResponse =
await _remoteCommandService.Execute(originId, targetId, muteCommand, args, server);
return string.Join(".", commandResponse.Select(result => result.Response));
@@ -272,21 +296,20 @@ private InteractionData CreateUnmuteInteraction(int targetClientId, Server serve
Type = "text",
};
- var inputs = new[] {reasonInput};
+ var inputs = new[] { reasonInput };
var inputsJson = JsonSerializer.Serialize(inputs);
return new InteractionData
{
EntityId = targetClientId,
- Name = Utilities.CurrentLocalization.LocalizationIndex[
- "WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"],
+ Name = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"],
DisplayMeta = "oi-volume-high",
ActionPath = "DynamicAction",
- ActionMeta = new()
+ ActionMeta = new Dictionary
{
- {"InteractionId", MuteInteraction},
- {"Outputs", reasonInput.Name},
- {"Inputs", inputsJson},
+ { "InteractionId", MuteInteraction },
+ { "Outputs", reasonInput.Name },
+ { "Inputs", inputsJson },
{
"ActionButtonLabel",
Utilities.CurrentLocalization.LocalizationIndex[
@@ -297,7 +320,7 @@ private InteractionData CreateUnmuteInteraction(int targetClientId, Server serve
Utilities.CurrentLocalization.LocalizationIndex[
"WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_UNMUTE"]
},
- {"ShouldRefresh", true.ToString()}
+ { "ShouldRefresh", true.ToString() }
},
MinimumPermission = Data.Models.Client.EFClient.Permission.Moderator,
Source = Name,