fix issue with view stats and reset stats failing

fix issue with set level returning wrong error message if setting a client to the same level they're currently at
update CoD4x parser version
update nuget packages
This commit is contained in:
RaidMax 2020-12-16 13:11:30 -06:00
parent 928cbef845
commit 4afc478076
11 changed files with 139 additions and 70 deletions

View File

@ -25,13 +25,13 @@
<ItemGroup>
<PackageReference Include="Jint" Version="3.0.0-beta-1632" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.7">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.7" />
<PackageReference Include="RestEase" Version="1.5.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.10" />
<PackageReference Include="RestEase" Version="1.5.1" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
<PropertyGroup>
@ -39,7 +39,6 @@
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
<TieredCompilation>true</TieredCompilation>
<LangVersion>Latest</LangVersion>
<StartupObject></StartupObject>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">

View File

@ -68,7 +68,10 @@ namespace IW4MAdmin.Application
private static async void OnCancelKey(object sender, ConsoleCancelEventArgs e)
{
ServerManager?.Stop();
await ApplicationTask;
if (ApplicationTask != null)
{
await ApplicationTask;
}
}
/// <summary>

View File

@ -25,12 +25,12 @@ var plugin = {
rconParser.Configuration.Dvar.AddMapping(110, 4); // dvar info
rconParser.Configuration.GuidNumberStyle = 7; // Integer
rconParser.Configuration.NoticeLineSeparator = '. '; // CoD4x does not support \n in the client notice
rconParser.Version = 'CoD4 X - win_mingw-x86 build 963 Mar 12 2019';
rconParser.Version = 'CoD4 X - win_mingw-x86 build 1056 Dec 12 2020';
rconParser.GameName = 1; // IW3
eventParser.Configuration.GameDirectory = 'main';
eventParser.Configuration.GuidNumberStyle = 7; // Integer
eventParser.Version = 'CoD4 X - win_mingw-x86 build 963 Mar 12 2019';
eventParser.Version = 'CoD4 X - win_mingw-x86 build 1056 Dec 12 2020';
eventParser.GameName = 1; // IW3
eventParser.URLProtocolFormat = 'cod4://{{ip}}:{{port}}';
},

View File

@ -23,40 +23,44 @@ namespace IW4MAdmin.Plugins.Stats.Commands
Permission = EFClient.Permission.User;
RequiresTarget = false;
AllowImpersonation = true;
_contextFactory = contextFactory;
}
public override async Task ExecuteAsync(GameEvent E)
public override async Task ExecuteAsync(GameEvent gameEvent)
{
if (E.Origin.ClientNumber >= 0)
if (gameEvent.Origin.ClientNumber >= 0)
{
var serverId = Helpers.StatManager.GetIdForServer(gameEvent.Owner);
long serverId = Helpers.StatManager.GetIdForServer(E.Owner);
EFClientStatistics clientStats;
await using var context = _contextFactory.CreateContext();
clientStats = await context.Set<EFClientStatistics>()
.Where(s => s.ClientId == E.Origin.ClientId)
var clientStats = await context.Set<EFClientStatistics>()
.Where(s => s.ClientId == gameEvent.Origin.ClientId)
.Where(s => s.ServerId == serverId)
.FirstAsync();
clientStats.Deaths = 0;
clientStats.Kills = 0;
clientStats.SPM = 0.0;
clientStats.Skill = 0.0;
clientStats.TimePlayed = 0;
// todo: make this more dynamic
clientStats.EloRating = 200.0;
.FirstOrDefaultAsync();
// want to prevent resetting stats before they've gotten any kills
if (clientStats != null)
{
clientStats.Deaths = 0;
clientStats.Kills = 0;
clientStats.SPM = 0.0;
clientStats.Skill = 0.0;
clientStats.TimePlayed = 0;
// todo: make this more dynamic
clientStats.EloRating = 200.0;
await context.SaveChangesAsync();
}
// reset the cached version
Plugin.Manager.ResetStats(E.Origin);
Plugin.Manager.ResetStats(gameEvent.Origin);
await context.SaveChangesAsync();
E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]);
gameEvent.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_SUCCESS"]);
}
else
{
E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_FAIL"]);
gameEvent.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_RESET_FAIL"]);
}
}
}

View File

@ -15,11 +15,10 @@ namespace IW4MAdmin.Plugins.Stats.Commands
public class ViewStatsCommand : Command
{
private readonly IDatabaseContextFactory _contextFactory;
public ViewStatsCommand(CommandConfiguration config, ITranslationLookup translationLookup,
public ViewStatsCommand(CommandConfiguration config, ITranslationLookup translationLookup,
IDatabaseContextFactory contextFactory) : base(config, translationLookup)
{
Name = "stats";
Description = translationLookup["PLUGINS_STATS_COMMANDS_VIEW_DESC"];
Alias = "xlrstats";
@ -33,17 +32,14 @@ namespace IW4MAdmin.Plugins.Stats.Commands
Required = false
}
};
_config = config;
_contextFactory = contextFactory;
}
private readonly CommandConfiguration _config;
public override async Task ExecuteAsync(GameEvent E)
{
string statLine;
EFClientStatistics pStats;
EFClientStatistics pStats = null;
if (E.Data.Length > 0 && E.Target == null)
{
@ -55,48 +51,67 @@ namespace IW4MAdmin.Plugins.Stats.Commands
}
}
long serverId = StatManager.GetIdForServer(E.Owner);
var serverId = StatManager.GetIdForServer(E.Owner);
// getting stats for a particular client
if (E.Target != null)
{
int performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Target.ClientId);
string performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
var performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Target.ClientId);
var performanceRankingString = performanceRanking == 0
? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"]
: $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Target)))
// target is currently connected so we want their cached stats if they exist
if (E.Owner.GetClientsAsList().Any(client => client.Equals(E.Target)))
{
pStats = E.Target.GetAdditionalProperty<EFClientStatistics>(StatManager.CLIENT_STATS_KEY);
}
else
// target is not connected so we want to look up via database
if (pStats == null)
{
await using var context = _contextFactory.CreateContext(false);
pStats = (await context.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
pStats = (await context.Set<EFClientStatistics>()
.FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
}
statLine = $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
// if it's still null then they've not gotten a kill or death yet
statLine = pStats == null
? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"]
: $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
}
// getting self stats
else
{
int performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Origin.ClientId);
string performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
var performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Origin.ClientId);
var performanceRankingString = performanceRanking == 0
? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"]
: $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Origin)))
// check if current client is connected to the server
if (E.Owner.GetClientsAsList().Any(client => client.Equals(E.Origin)))
{
pStats = E.Origin.GetAdditionalProperty<EFClientStatistics>(StatManager.CLIENT_STATS_KEY);
}
else
// happens if the user has not gotten a kill/death since connecting
if (pStats == null)
{
await using var context = _contextFactory.CreateContext(false);
pStats = (await context.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId));
pStats = (await context.Set<EFClientStatistics>()
.FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId));
}
statLine = $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
// if it's still null then they've not gotten a kill or death yet
statLine = pStats == null
? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"]
: $"^5{pStats.Kills} ^7{_translationLookup["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{_translationLookup["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{_translationLookup["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
}
if (E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix))
{
string name = E.Target == null ? E.Origin.Name : E.Target.Name;
var name = E.Target == null ? E.Origin.Name : E.Target.Name;
E.Owner.Broadcast(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(name));
E.Owner.Broadcast(statLine);
}
@ -112,4 +127,4 @@ namespace IW4MAdmin.Plugins.Stats.Commands
}
}
}
}
}

View File

@ -1161,6 +1161,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
public void ResetStats(EFClient client)
{
var stats = client.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
// the cached stats have not been loaded yet
if (stats == null)
{
return;
}
stats.Kills = 0;
stats.Deaths = 0;
stats.SPM = 0;

View File

@ -725,6 +725,12 @@ namespace SharedLibraryCore.Commands
gameEvent.Origin.Tell($"{_translationLookup["COMMANDS_SETLEVEL_STEPPEDDISABLED"]} ^5{gameEvent.Target.Name}");
return;
}
else if (gameEvent.Target.Level == Permission.Flagged)
{
gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_FLAGGED"].FormatExt(gameEvent.Target.Name));
return;
}
// stepped privilege is enabled, but the new level is too high
else if (steppedPrivileges && !canPromoteSteppedPriv)
@ -748,9 +754,19 @@ namespace SharedLibraryCore.Commands
if (result.Failed)
{
// user is the same level
if (result.FailReason == GameEvent.EventFailReason.Invalid)
{
gameEvent.Origin.Tell(_translationLookup["COMMANDS_SETLEVEL_INVALID"]
.FormatExt(gameEvent.Target.Name, newPerm.ToString()));
return;
}
using (LogContext.PushProperty("Server", gameEvent.Origin.CurrentServer?.ToString()))
{
logger.LogWarning("Failed to set level of client {origin}", gameEvent.Origin.ToString());
logger.LogWarning("Failed to set level of client {origin} {reason}",
gameEvent.Origin.ToString(),
result.FailReason);
}
gameEvent.Origin.Tell(_translationLookup["SERVER_ERROR_COMMAND_INGAME"]);
return;

View File

@ -28,35 +28,35 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="9.1.3" />
<PackageReference Include="FluentValidation" Version="9.3.0" />
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.ru" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.de" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.es" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.pt" Version="2.8.26" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.7">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.10" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Npgsql" Version="4.1.4" />
<PackageReference Include="Npgsql" Version="4.1.7" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.2.4" />
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.10" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@ -6,9 +6,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="6.2.0" />
<PackageReference Include="FakeItEasy" Version="6.2.1" />
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0">
<PrivateAssets>all</PrivateAssets>

View File

@ -532,6 +532,31 @@ namespace ApplicationTests
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.ChangePermission && !_event.Failed));
}
[Test]
public async Task Test_SetLevelFail_WhenFlagged()
{
var server = serviceProvider.GetRequiredService<IW4MServer>();
var cmd = serviceProvider.GetRequiredService<SetLevelCommand>();
var origin = ClientGenerators.CreateBasicClient(server);
origin.Level = Permission.Owner;
var target = ClientGenerators.CreateBasicClient(server);
target.Level = Permission.Flagged;
var gameEvent = new GameEvent()
{
Target = target,
Origin = origin,
Data = "Banned",
Owner = server,
};
await cmd.ExecuteAsync(gameEvent);
Assert.AreEqual(Permission.Flagged, target.Level);
Assert.IsNotEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.Tell));
Assert.IsEmpty(mockEventHandler.Events.Where(_event => _event.Type == GameEvent.EventType.ChangePermission));
}
#endregion
#region PREFIX_PROCESSING

View File

@ -68,8 +68,8 @@
<ItemGroup>
<PackageReference Include="BuildWebCompiler" Version="1.12.405" />
<PackageReference Include="BundlerMinifier.Core" Version="3.2.449" />
<PackageReference Include="FluentValidation.AspNetCore" Version="9.1.2" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.76" />
<PackageReference Include="FluentValidation.AspNetCore" Version="9.3.0" />
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.113" />
</ItemGroup>
<ItemGroup>