Fix Threading Duplicate for Mute Penalty & Added !MuteInfo & Fix PM (#269)

* Resolve duplicate migration
Resolve unmuting state double penalties

* Change order of operation

* Added MuteInfoCommand.cs

* Resolve !pm and @broadcast permanently being disabled
This commit is contained in:
Amos 2022-10-14 14:47:01 +01:00 committed by GitHub
parent 76925a78d4
commit cf51b83cdd
3 changed files with 102 additions and 34 deletions

View File

@ -0,0 +1,50 @@
using Data.Models.Client;
using Humanizer;
using SharedLibraryCore;
using SharedLibraryCore.Commands;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Interfaces;
namespace Mute.Commands;
public class MuteInfoCommand : Command
{
public MuteInfoCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config,
translationLookup)
{
Name = "muteinfo";
Description = translationLookup["PLUGINS_MUTE_COMMANDS_MUTEINFO_DESC"];
Alias = "mi";
Permission = EFClient.Permission.Moderator;
RequiresTarget = true;
SupportedGames = Plugin.SupportedGames;
Arguments = new[]
{
new CommandArgument
{
Name = translationLookup["COMMANDS_ARGS_PLAYER"],
Required = true
}
};
}
public override async Task ExecuteAsync(GameEvent gameEvent)
{
var currentMuteMeta = await Plugin.MuteManager.GetCurrentMuteState(gameEvent.Target);
switch (currentMuteMeta.MuteState)
{
case MuteState.Muted when currentMuteMeta.Expiration is null:
gameEvent.Origin.Tell(_translationLookup["PLUGINS_MUTE_COMMANDS_MUTEINFO_SUCCESS"]
.FormatExt(gameEvent.Target.Name, currentMuteMeta.Reason));
return;
case MuteState.Muted when currentMuteMeta.Expiration.HasValue && currentMuteMeta.Expiration.Value > DateTime.UtcNow:
var remainingTime = (currentMuteMeta.Expiration.Value - DateTime.UtcNow).HumanizeForCurrentCulture();
gameEvent.Origin.Tell(_translationLookup["PLUGINS_MUTE_COMMANDS_MUTEINFO_TM_SUCCESS"]
.FormatExt(gameEvent.Target.Name, currentMuteMeta.Reason, remainingTime));
return;
default:
gameEvent.Origin.Tell(_translationLookup["PLUGINS_MUTE_COMMANDS_MUTEINFO_NONE"]);
break;
}
}
}

View File

@ -13,6 +13,7 @@ public class MuteManager
private readonly IMetaServiceV2 _metaService; private readonly IMetaServiceV2 _metaService;
private readonly ITranslationLookup _translationLookup; private readonly ITranslationLookup _translationLookup;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly SemaphoreSlim _onMuteAction = new(1, 1);
public MuteManager(IMetaServiceV2 metaService, ITranslationLookup translationLookup, ILogger logger) public MuteManager(IMetaServiceV2 metaService, ITranslationLookup translationLookup, ILogger logger)
{ {
@ -26,38 +27,46 @@ public class MuteManager
public async Task<MuteStateMeta> GetCurrentMuteState(EFClient client) public async Task<MuteStateMeta> GetCurrentMuteState(EFClient client)
{ {
var clientMuteMeta = await ReadPersistentDataV2(client); try
if (clientMuteMeta is not null) return clientMuteMeta;
// Return null if the client doesn't have old or new meta.
var muteState = await ReadPersistentDataV1(client);
clientMuteMeta = new MuteStateMeta
{ {
Reason = muteState is null ? string.Empty : _translationLookup["PLUGINS_MUTE_MIGRATED"], await _onMuteAction.WaitAsync();
Expiration = muteState switch var clientMuteMeta = await ReadPersistentDataV2(client);
if (clientMuteMeta is not null) return clientMuteMeta;
// Return null if the client doesn't have old or new meta.
var muteState = await ReadPersistentDataV1(client);
clientMuteMeta = new MuteStateMeta
{ {
null => DateTime.UtcNow, Reason = muteState is null ? string.Empty : _translationLookup["PLUGINS_MUTE_MIGRATED"],
MuteState.Muted => null, Expiration = muteState switch
_ => DateTime.UtcNow {
}, null => DateTime.UtcNow,
MuteState = muteState ?? MuteState.Unmuted, MuteState.Muted => null,
CommandExecuted = true _ => DateTime.UtcNow
}; },
MuteState = muteState ?? MuteState.Unmuted,
CommandExecuted = true
};
// Migrate old mute meta, else, client has no state, so set a generic one, but don't write it to database. // Migrate old mute meta, else, client has no state, so set a generic one, but don't write it to database.
if (muteState is not null) if (muteState is not null)
{ {
clientMuteMeta.CommandExecuted = false; clientMuteMeta.CommandExecuted = false;
await WritePersistentData(client, clientMuteMeta); await WritePersistentData(client, clientMuteMeta);
await CreatePenalty(muteState.Value, Utilities.IW4MAdminClient(), client, clientMuteMeta.Expiration, await CreatePenalty(muteState.Value, Utilities.IW4MAdminClient(), client, clientMuteMeta.Expiration,
clientMuteMeta.Reason); clientMuteMeta.Reason);
} }
else else
{ {
client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta); client.SetAdditionalProperty(Plugin.MuteKey, clientMuteMeta);
} }
return clientMuteMeta; return clientMuteMeta;
}
finally
{
if (_onMuteAction.CurrentCount == 0) _onMuteAction.Release();
}
} }
public async Task<bool> Mute(Server server, EFClient origin, EFClient target, DateTime? dateTime, string reason) public async Task<bool> Mute(Server server, EFClient origin, EFClient target, DateTime? dateTime, string reason)
@ -65,8 +74,6 @@ public class MuteManager
var clientMuteMeta = await GetCurrentMuteState(target); var clientMuteMeta = await GetCurrentMuteState(target);
if (clientMuteMeta.MuteState is MuteState.Muted && clientMuteMeta.CommandExecuted) return false; if (clientMuteMeta.MuteState is MuteState.Muted && clientMuteMeta.CommandExecuted) return false;
await CreatePenalty(MuteState.Muted, origin, target, dateTime, reason);
clientMuteMeta = new MuteStateMeta clientMuteMeta = new MuteStateMeta
{ {
Expiration = dateTime, Expiration = dateTime,
@ -76,6 +83,8 @@ public class MuteManager
}; };
await WritePersistentData(target, clientMuteMeta); await WritePersistentData(target, clientMuteMeta);
await CreatePenalty(MuteState.Muted, origin, target, dateTime, reason);
// Handle game command // Handle game command
var client = server.GetClientsAsList().FirstOrDefault(client => client.NetworkId == target.NetworkId); var client = server.GetClientsAsList().FirstOrDefault(client => client.NetworkId == target.NetworkId);
await PerformGameCommand(server, client, clientMuteMeta); await PerformGameCommand(server, client, clientMuteMeta);
@ -89,7 +98,10 @@ public class MuteManager
if (clientMuteMeta.MuteState is MuteState.Unmuted && clientMuteMeta.CommandExecuted) return false; if (clientMuteMeta.MuteState is MuteState.Unmuted && clientMuteMeta.CommandExecuted) return false;
if (!target.IsIngame && clientMuteMeta.MuteState is MuteState.Unmuting) return false; if (!target.IsIngame && clientMuteMeta.MuteState is MuteState.Unmuting) return false;
await CreatePenalty(MuteState.Unmuted, origin, target, DateTime.UtcNow, reason); if (clientMuteMeta.MuteState is not MuteState.Unmuting)
{
await CreatePenalty(MuteState.Unmuted, origin, target, DateTime.UtcNow, reason);
}
clientMuteMeta = new MuteStateMeta clientMuteMeta = new MuteStateMeta
{ {

View File

@ -38,9 +38,6 @@ public class Plugin : IPlugin
switch (gameEvent.Type) switch (gameEvent.Type)
{ {
case GameEvent.EventType.Command:
break;
case GameEvent.EventType.Join: case GameEvent.EventType.Join:
// Check if user has any meta set, else ignore (unmuted) // Check if user has any meta set, else ignore (unmuted)
var muteMetaJoin = await MuteManager.GetCurrentMuteState(gameEvent.Origin); var muteMetaJoin = await MuteManager.GetCurrentMuteState(gameEvent.Origin);
@ -122,7 +119,16 @@ public class Plugin : IPlugin
manager.CommandInterceptors.Add(gameEvent => manager.CommandInterceptors.Add(gameEvent =>
{ {
if (gameEvent.Extra is not Command command) if (gameEvent.Extra is not Command command)
{
return true; return true;
}
var muteMeta = MuteManager.GetCurrentMuteState(gameEvent.Origin).GetAwaiter().GetResult();
if (muteMeta.MuteState is not MuteState.Muted)
{
return true;
}
return !DisabledCommands.Contains(command.GetType().Name) && !command.IsBroadcast; return !DisabledCommands.Contains(command.GetType().Name) && !command.IsBroadcast;
}); });