diff --git a/GameFiles/GameInterface/_integration_iw5.gsc b/GameFiles/GameInterface/_integration_iw5.gsc index fd4d652a..6dfc6a7c 100644 --- a/GameFiles/GameInterface/_integration_iw5.gsc +++ b/GameFiles/GameInterface/_integration_iw5.gsc @@ -193,7 +193,7 @@ NoClipImpl() self God(); self Noclip(); - self Hide(); + self Show(); SetDvar( "sv_cheats", 0 ); 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 *';