From a9dd4e66b6711eae7f046dbe8eff262137989f6a Mon Sep 17 00:00:00 2001 From: Amos Date: Sun, 21 Jan 2024 16:05:17 +0000 Subject: [PATCH] Add mute/unmute functionality and update related components Added mute and unmute commands in ParserIW6x.js, including necessary updates in MuteManager.cs and Plugin.cs files. Refactored the query for mute penalties. Also added RootNamespace in Mute.csproj. --- Plugins/Mute/Mute.csproj | 1 + Plugins/Mute/MuteManager.cs | 23 ++++++++------- Plugins/Mute/Plugin.cs | 45 +++++++++++++++++++++++------ Plugins/ScriptPlugins/ParserIW4x.js | 2 ++ Plugins/ScriptPlugins/ParserIW6x.js | 2 ++ 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Plugins/Mute/Mute.csproj b/Plugins/Mute/Mute.csproj index a89ad5ba..460888bd 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 5f91d816..537465b1 100644 --- a/Plugins/Mute/MuteManager.cs +++ b/Plugins/Mute/MuteManager.cs @@ -131,8 +131,11 @@ public class MuteManager { var newPenalty = new EFPenalty { - Type = muteState is MuteState.Unmuted ? EFPenalty.PenaltyType.Unmute : - dateTime is null ? EFPenalty.PenaltyType.Mute : EFPenalty.PenaltyType.TempMute, + Type = muteState is MuteState.Unmuted + ? EFPenalty.PenaltyType.Unmute + : dateTime is null + ? EFPenalty.PenaltyType.Mute + : EFPenalty.PenaltyType.TempMute, Expires = muteState is MuteState.Unmuted ? DateTime.UtcNow : dateTime, Offender = target, Offense = reason, @@ -148,10 +151,9 @@ public class MuteManager { await using var context = _databaseContextFactory.CreateContext(); var mutePenalties = await context.Penalties - .Where(penalty => penalty.OffenderId == client.ClientId && - (penalty.Type == EFPenalty.PenaltyType.Mute || - penalty.Type == EFPenalty.PenaltyType.TempMute) && - (penalty.Expires == null || penalty.Expires > DateTime.UtcNow)) + .Where(penalty => penalty.OffenderId == client.ClientId) + .Where(penalty => penalty.Type == EFPenalty.PenaltyType.Mute || penalty.Type == EFPenalty.PenaltyType.TempMute) + .Where(penalty => penalty.Expires == null || penalty.Expires > DateTime.UtcNow) .ToListAsync(); foreach (var mutePenalty in mutePenalties) @@ -169,19 +171,20 @@ public class MuteManager switch (muteStateMeta.MuteState) { case MuteState.Muted: - await server.ExecuteCommandAsync($"muteClient {client.ClientNumber}"); + var muteCommand = string.Format(server.RconParser.Configuration.CommandPrefixes.Mute, client.ClientNumber); + await server.ExecuteCommandAsync(muteCommand); muteStateMeta.CommandExecuted = true; break; case MuteState.Unmuted: - await server.ExecuteCommandAsync($"unmute {client.ClientNumber}"); + var unMuteCommand = string.Format(server.RconParser.Configuration.CommandPrefixes.Unmute, client.ClientNumber); + await server.ExecuteCommandAsync(unMuteCommand); muteStateMeta.CommandExecuted = true; break; } } 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; diff --git a/Plugins/Mute/Plugin.cs b/Plugins/Mute/Plugin.cs index 242857da..fc75ea27 100644 --- a/Plugins/Mute/Plugin.cs +++ b/Plugins/Mute/Plugin.cs @@ -21,7 +21,7 @@ public class Plugin : IPluginV2 public const string MuteKey = "IW4MMute"; public static IManager Manager { get; private set; } = null!; - public static readonly Server.Game[] SupportedGames = {Server.Game.IW4}; + public static Server.Game[] SupportedGames { get; private set; } = Array.Empty(); private static readonly string[] DisabledCommands = {nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"}; private readonly IInteractionRegistration _interactionRegistration; private readonly IRemoteCommandService _remoteCommandService; @@ -34,12 +34,14 @@ public class Plugin : IPluginV2 _interactionRegistration = interactionRegistration; _remoteCommandService = remoteCommandService; _muteManager = muteManager; - + IManagementEventSubscriptions.Load += OnLoad; IManagementEventSubscriptions.Unload += OnUnload; - IManagementEventSubscriptions.ClientStateInitialized += OnClientStateInitialized; + IGameServerEventSubscriptions.ClientDataUpdated += OnClientDataUpdated; + IGameServerEventSubscriptions.MonitoringStarted += OnServerMonitoredStarted; + IGameEventSubscriptions.ClientMessaged += OnClientMessaged; } @@ -61,7 +63,7 @@ public class Plugin : IPluginV2 var muteMeta = Task.Run(() => _muteManager.GetCurrentMuteState(gameEvent.Origin), cancellationToken) .GetAwaiter().GetResult(); - + if (muteMeta.MuteState is not MuteState.Muted) { return true; @@ -91,7 +93,7 @@ public class Plugin : IPluginV2 }); return Task.CompletedTask; } - + private Task OnUnload(IManager manager, CancellationToken token) { _interactionRegistration.UnregisterInteraction(MuteInteraction); @@ -152,21 +154,21 @@ public class Plugin : IPluginV2 { return; } - + var muteMetaJoin = await _muteManager.GetCurrentMuteState(state.Client); 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); @@ -319,4 +321,29 @@ public class Plugin : IPluginV2 } }; } + + private Task OnServerMonitoredStarted(MonitorStartEvent serverEvent, CancellationToken token) + { + var game = (Server.Game)serverEvent.Server.GameCode; + + lock (SupportedGames) + { + if (SupportedGames.Contains(game)) + { + return Task.CompletedTask; + } + + var server = Manager.GetServers().FirstOrDefault(x => x == serverEvent.Server); + var commandIsEmpty = string.IsNullOrWhiteSpace(server?.RconParser.Configuration.CommandPrefixes.Mute); + + if (commandIsEmpty) + { + return Task.CompletedTask; + } + + SupportedGames = SupportedGames.Append(game).ToArray(); + } + + return Task.CompletedTask; + } } diff --git a/Plugins/ScriptPlugins/ParserIW4x.js b/Plugins/ScriptPlugins/ParserIW4x.js index b35ef0d0..0d9cf3a2 100644 --- a/Plugins/ScriptPlugins/ParserIW4x.js +++ b/Plugins/ScriptPlugins/ParserIW4x.js @@ -19,6 +19,8 @@ var plugin = { rconParser.Configuration.CommandPrefixes.Kick = 'clientkick {0} "{1}"'; rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"'; rconParser.Configuration.CommandPrefixes.TempBan = 'tempbanclient {0} "{1}"'; + rconParser.Configuration.CommandPrefixes.Mute = 'muteClient {0}'; + rconParser.Configuration.CommandPrefixes.Unmute = 'unmute {0}'; rconParser.Configuration.DefaultRConPort = 28960; rconParser.Configuration.DefaultInstallationDirectoryHint = 'HKEY_CURRENT_USER\\Software\\Classes\\iw4x\\shell\\open\\command'; diff --git a/Plugins/ScriptPlugins/ParserIW6x.js b/Plugins/ScriptPlugins/ParserIW6x.js index 7c399aa8..4185bb35 100644 --- a/Plugins/ScriptPlugins/ParserIW6x.js +++ b/Plugins/ScriptPlugins/ParserIW6x.js @@ -20,6 +20,8 @@ var plugin = { rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"'; rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0} "{1}"'; rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n'; + rconParser.Configuration.CommandPrefixes.Mute = 'muteClient {0}'; + rconParser.Configuration.CommandPrefixes.Unmute = 'unmuteClient {0}'; rconParser.Configuration.Dvar.Pattern = '^ *\\"(.+)\\" is: \\"(.+)?\\" default: \\"(.+)?\\"\\n?(?:latched: \\"(.+)?\\"\\n?)?(.*)$'; rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(Yes|No) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$'; rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';