update application version

ignore stat events of bots if they are ignored
limit max number of bot profiles to 18, greater than 18 wraps
prevent anti cheat from running on bot events
create localization folder on publish so copying over doesn't fail
include quick message mapping on webfront server history chat
make gravatar on profile not repeat
This commit is contained in:
RaidMax 2019-04-25 13:00:54 -05:00
parent 03ae3b5822
commit 02622ea7de
10 changed files with 78 additions and 71 deletions

View File

@ -6,7 +6,7 @@
<RuntimeFrameworkVersion>2.2.2</RuntimeFrameworkVersion>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
<Version>2.2.6.4</Version>
<Version>2.2.6.5</Version>
<Authors>RaidMax</Authors>
<Company>Forever None</Company>
<Product>IW4MAdmin</Product>
@ -31,8 +31,8 @@
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
<TieredCompilation>true</TieredCompilation>
<AssemblyVersion>2.2.6.4</AssemblyVersion>
<FileVersion>2.2.6.4</FileVersion>
<AssemblyVersion>2.2.6.5</AssemblyVersion>
<FileVersion>2.2.6.5</FileVersion>
</PropertyGroup>
<ItemGroup>

View File

@ -133,7 +133,7 @@ namespace IW4MAdmin.Application
catch (Exception ex)
{
newEvent.FailReason = GameEvent.EventFailReason.Exception;
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {newEvent.Owner}");
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"].FormatExt(newEvent.Owner));
Logger.WriteDebug(ex.GetExceptionInfo());
}

View File

@ -97,6 +97,16 @@ if "%CurrentConfiguration%" == "Release" (
if exist "%SolutionDir%Publish\Windows\refs" move "%SolutionDir%Publish\Windows\refs" "%SolutionDir%Publish\Windows\Lib\refs"
)
if "%CurrentConfiguration%" == "Prerelease" (
echo PR-LOC
if not exist "%SolutionDir%Publish\WindowsPrerelease\Localization" md "%SolutionDir%Publish\WindowsPrerelease\Localization"
)
if "%CurrentConfiguration%" == "Release" (
echo R-LOC
if not exist "%SolutionDir%Publish\Windows\Localization" md "%SolutionDir%Publish\Windows\Localization"
)
echo making start scripts
@(echo @echo off && echo @title IW4MAdmin && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\WindowsPrerelease\StartIW4MAdmin.cmd"
@(echo @echo off && echo @title IW4MAdmin && echo dotnet Lib\IW4MAdmin.dll && echo pause) > "%SolutionDir%Publish\Windows\StartIW4MAdmin.cmd"

View File

@ -189,6 +189,10 @@ namespace IW4MAdmin
if (E.Type == GameEvent.EventType.ConnectionRestored)
{
if (Throttled)
{
Logger.WriteVerbose(loc["MANAGER_CONNECTION_REST"].FormatExt($"[{IP}:{Port}]"));
}
Logger.WriteInfo("Connection restored to server, so we are no longer throttling the poll rate");
Throttled = false;
}
@ -390,18 +394,27 @@ namespace IW4MAdmin
{
E.Data = E.Data.StripColors();
if (E.Data.Length > 0)
if (E.Data?.Length > 0)
{
// this may be a fix for a hard to reproduce null exception error
lock (ChatHistory)
string message = E.Data;
if (E.Data.IsQuickMessage())
{
ChatHistory.Add(new ChatInfo()
try
{
Name = E.Origin.Name,
Message = E.Data ?? "NULL",
Time = DateTime.UtcNow
});
message = Manager.GetApplicationSettings().Configuration()
.QuickMessages
.First(_qm => _qm.Game == GameName)
.Messages[E.Data.Substring(1)];
}
catch { }
}
ChatHistory.Add(new ChatInfo()
{
Name = E.Origin.Name,
Message = message,
Time = DateTime.UtcNow
});
}
}
@ -649,8 +662,6 @@ namespace IW4MAdmin
if (ConnectionErrors > 0)
{
Logger.WriteVerbose(loc["MANAGER_CONNECTION_REST"].FormatExt($"[{IP}:{Port}]"));
var _event = new GameEvent()
{
Type = GameEvent.EventType.ConnectionRestored,
@ -921,7 +932,7 @@ namespace IW4MAdmin
#if !DEBUG
else
{
string formattedKick = String.Format(RconParser.Configuration.CommandPrefixes.Kick, Target.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
string formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick, Target.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7");
await Target.CurrentServer.ExecuteCommandAsync(formattedKick);
}
#endif

View File

@ -91,7 +91,6 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers
.First(_qm => _qm.Game == message.ServerGame);
message.Message = quickMessages.Messages[message.Message.Substring(1)];
message.IsQuickMessage = true;
}
catch { }
}

View File

@ -13,7 +13,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
@ -537,7 +536,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return;
}
// incase the add palyer event get delayed
// incase the add player event get delayed
if (!Servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
{
await AddPlayer(attacker);
@ -571,7 +570,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
ctx.Set<EFClientKill>().Add(hit);
}
if (Plugin.Config.Configuration().EnableAntiCheat)
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot)
{
if (clientDetection.QueuedHits.Count > Detection.QUEUE_COUNT)
{
@ -580,7 +579,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
clientDetection.QueuedHits = clientDetection.QueuedHits.OrderBy(_hits => _hits.TimeOffset).ToList();
var oldestHit = clientDetection.QueuedHits.First();
clientDetection.QueuedHits.RemoveAt(0);
ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), clientDetection, attacker, ctx);
await ApplyPenalty(clientDetection.ProcessHit(oldestHit, isDamage), clientDetection, attacker, ctx);
}
}
@ -589,7 +588,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
clientDetection.QueuedHits.Add(hit);
}
ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
await ApplyPenalty(clientDetection.ProcessTotalRatio(clientStats), clientDetection, attacker, ctx);
}
ctx.Set<EFHitLocationCount>().UpdateRange(clientStats.HitLocations);
@ -607,8 +606,9 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
}
}
void ApplyPenalty(DetectionPenaltyResult penalty, Detection clientDetection, EFClient attacker, DatabaseContext ctx)
async Task ApplyPenalty(DetectionPenaltyResult penalty, Detection clientDetection, EFClient attacker, DatabaseContext ctx)
{
var penaltyClient = Utilities.IW4MAdminClient(attacker.CurrentServer);
switch (penalty.ClientPenalty)
{
case Penalty.PenaltyType.Ban:
@ -616,22 +616,19 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{
break;
}
attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new EFClient()
{
ClientId = 1,
AdministeredPenalties = new List<EFPenalty>()
{
new EFPenalty()
{
AutomatedOffense = penalty.Type == Cheat.Detection.DetectionType.Bone ?
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
}
},
Level = EFClient.Permission.Console,
CurrentServer = attacker.CurrentServer,
}, false);
penaltyClient.AdministeredPenalties = new List<EFPenalty>()
{
new EFPenalty()
{
AutomatedOffense = penalty.Type == Detection.DetectionType.Bone ?
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
}
};
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], penaltyClient, false).WaitAsync();
if (clientDetection.Tracker.HasChanges)
{
SaveTrackedSnapshots(clientDetection, ctx);
@ -647,23 +644,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}";
attacker.Flag(flagReason, new EFClient()
{
ClientId = 1,
Level = EFClient.Permission.Console,
CurrentServer = attacker.CurrentServer,
});
await attacker.Flag(flagReason, penaltyClient).WaitAsync();
if (clientDetection.Tracker.HasChanges)
{
SaveTrackedSnapshots(clientDetection, ctx);
}
break;
}
}
void SaveTrackedSnapshots(Cheat.Detection clientDetection, DatabaseContext ctx)
void SaveTrackedSnapshots(Detection clientDetection, DatabaseContext ctx)
{
// todo: why does this cause duplicate primary key
var change = clientDetection.Tracker.GetNextChange();

View File

@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
using SharedLibraryCore;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos;
using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces;
@ -76,13 +77,8 @@ namespace IW4MAdmin.Plugins.Stats
break;
case GameEvent.EventType.ScriptKill:
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 14)
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
{
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
@ -99,13 +95,8 @@ namespace IW4MAdmin.Plugins.Stats
}
break;
case GameEvent.EventType.Kill:
if (!E.Owner.CustomCallback)
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
{
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
@ -121,13 +112,8 @@ namespace IW4MAdmin.Plugins.Stats
}
break;
case GameEvent.EventType.Damage:
if (!E.Owner.CustomCallback)
if (!E.Owner.CustomCallback && !ShouldIgnoreEvent(E.Origin, E.Target))
{
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
@ -144,13 +130,8 @@ namespace IW4MAdmin.Plugins.Stats
break;
case GameEvent.EventType.ScriptDamage:
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 14)
if (killInfo.Length >= 14 && !ShouldIgnoreEvent(E.Origin, E.Target))
{
if (E.Origin.ClientId <= 1 && E.Target.ClientId <= 1)
{
return;
}
// this treats "world" damage as self damage
if (E.Origin.ClientId <= 1)
{
@ -500,5 +481,17 @@ namespace IW4MAdmin.Plugins.Stats
await Manager.Sync(sv);
}
}
/// <summary>
/// Indicates if the event should be ignored
/// (If the client id or target id is not a real client or the target/origin is a bot and ignore bots is turned on)
/// </summary>
/// <param name="origin"></param>
/// <param name="target"></param>
/// <returns></returns>
private bool ShouldIgnoreEvent(EFClient origin, EFClient target)
{
return ((origin.ClientId <= 1 && target.ClientId <= 1) || (target.IsBot || origin.IsBot) && ServerManager.GetApplicationSettings().Configuration().IgnoreBots);
}
}
}

View File

@ -267,7 +267,7 @@ namespace SharedLibraryCore
public override string ToString()
{
return $"{IP}-{Port}";
return $"{IP}:{Port}";
}
protected async Task<bool> ScriptLoaded()

View File

@ -269,6 +269,7 @@ namespace SharedLibraryCore
public static long ConvertLong(this string str)
{
str = str.Substring(0, Math.Min(str.Length, 16));
int maxBots = 18;
long id;
if (str.Length <= 11) // 10 numeric characters + signed character
@ -288,7 +289,7 @@ namespace SharedLibraryCore
if (!string.IsNullOrEmpty(bot))
{
// should set their GUID to the negation of their 1 based index (-1 - -18)
return -(Convert.ToInt64(bot.Substring(3)) + 1);
return -(Convert.ToInt64(bot.Substring(3)) + 1) % maxBots;
}
return long.MinValue;

View File

@ -153,6 +153,8 @@
min-width: 8rem;
min-height: 8rem;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.profile-shortcode {