update change tracking and elo
master shows monitoring server count master can provide individual localizations
This commit is contained in:
parent
4d585e6ab2
commit
be68335f70
@ -8,7 +8,7 @@ using RestEase;
|
|||||||
namespace IW4MAdmin.Application.API.Master
|
namespace IW4MAdmin.Application.API.Master
|
||||||
{
|
{
|
||||||
public class AuthenticationId
|
public class AuthenticationId
|
||||||
{
|
{
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
}
|
}
|
||||||
@ -62,6 +62,9 @@ namespace IW4MAdmin.Application.API.Master
|
|||||||
Task<VersionInfo> GetVersion();
|
Task<VersionInfo> GetVersion();
|
||||||
|
|
||||||
[Get("localization")]
|
[Get("localization")]
|
||||||
Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization();
|
Task<List<SharedLibraryCore.Localization.Layout>> GetLocalization();
|
||||||
|
|
||||||
|
[Get("localization/{languageTag}")]
|
||||||
|
Task<SharedLibraryCore.Localization.Layout> GetLocalization([Path("languageTag")] string languageTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,8 @@ namespace IW4MAdmin.Application.Localization
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var api = Endpoint.Get();
|
var api = Endpoint.Get();
|
||||||
var localizations = api.GetLocalization().Result;
|
var localization = api.GetLocalization(currentLocale).Result;
|
||||||
|
Utilities.CurrentLocalization = localization;
|
||||||
var usingLocale = localizations.FirstOrDefault(l => l.LocalizationName == currentLocale
|
|
||||||
|| l.LocalizationName.Substring(0, 2) == currentLocale.Substring(0, 2)) ??
|
|
||||||
localizations.First();
|
|
||||||
|
|
||||||
Utilities.CurrentLocalization = usingLocale;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ namespace Application.RconParsers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this happens if status is requested while map is rotating
|
// this happens if status is requested while map is rotating
|
||||||
if (Status[1] == "Server Initialization")
|
if (Status.Contains("Server Initialization"))
|
||||||
{
|
{
|
||||||
throw new ServerException("Server is rotating map");
|
throw new ServerException("Server is rotating map");
|
||||||
}
|
}
|
||||||
@ -139,6 +139,7 @@ namespace Application.RconParsers
|
|||||||
{
|
{
|
||||||
IW4MAdmin.Application.Program.ServerManager.Logger.WriteDebug(s);
|
IW4MAdmin.Application.Program.ServerManager.Logger.WriteDebug(s);
|
||||||
}
|
}
|
||||||
|
throw new ServerException("Bad status received");
|
||||||
}
|
}
|
||||||
|
|
||||||
return StatusPlayers;
|
return StatusPlayers;
|
||||||
|
@ -58,25 +58,25 @@
|
|||||||
<Compile Include="master\models\__init__.py">
|
<Compile Include="master\models\__init__.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\authenticate.py">
|
<Compile Include="master\resources\authenticate.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="master\resources\history_graph.py">
|
<Compile Include="master\resources\history_graph.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\instance.py">
|
<Compile Include="master\resources\instance.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\localization.py">
|
<Compile Include="master\resources\localization.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\null.py">
|
<Compile Include="master\resources\null.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\version.py">
|
<Compile Include="master\resources\version.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Master\resources\__init__.py">
|
<Compile Include="master\resources\__init__.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="master\routes.py">
|
<Compile Include="master\routes.py">
|
||||||
@ -98,22 +98,21 @@
|
|||||||
<Compile Include="master\views.py" />
|
<Compile Include="master\views.py" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="C:\Projects\IW4M-Admin\Master\master\" />
|
|
||||||
<Folder Include="master\" />
|
<Folder Include="master\" />
|
||||||
<Folder Include="master\context\" />
|
<Folder Include="master\context\" />
|
||||||
<Folder Include="master\models\" />
|
<Folder Include="master\models\" />
|
||||||
<Folder Include="master\config\" />
|
<Folder Include="master\config\" />
|
||||||
<Folder Include="master\schema\" />
|
<Folder Include="master\schema\" />
|
||||||
<Folder Include="Master\resources\" />
|
<Folder Include="Master\resources\" />
|
||||||
<Folder Include="Master\static\" />
|
<Folder Include="master\static\" />
|
||||||
<Folder Include="Master\templates\" />
|
<Folder Include="master\templates\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="FolderProfile.pubxml" />
|
<None Include="FolderProfile.pubxml" />
|
||||||
<Content Include="master\config\master.json" />
|
<Content Include="master\config\master.json" />
|
||||||
<Content Include="requirements.txt" />
|
<Content Include="requirements.txt" />
|
||||||
<Content Include="Master\templates\index.html" />
|
<Content Include="master\templates\index.html" />
|
||||||
<Content Include="Master\templates\layout.html" />
|
<Content Include="master\templates\layout.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Interpreter Include="dev_env\">
|
<Interpreter Include="dev_env\">
|
||||||
|
@ -8,7 +8,7 @@ import csv
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
class Localization(Resource):
|
class Localization(Resource):
|
||||||
def get(self):
|
def list(self):
|
||||||
response = urllib.request.urlopen('https://docs.google.com/spreadsheets/d/e/2PACX-1vRQjCqPvd0Xqcn86WqpFqp_lx4KKpel9O4OV13NycmV8rmqycorgJQm-8qXMfw37QJHun3pqVZFUKG-/pub?gid=0&single=true&output=csv')
|
response = urllib.request.urlopen('https://docs.google.com/spreadsheets/d/e/2PACX-1vRQjCqPvd0Xqcn86WqpFqp_lx4KKpel9O4OV13NycmV8rmqycorgJQm-8qXMfw37QJHun3pqVZFUKG-/pub?gid=0&single=true&output=csv')
|
||||||
data = response.read().decode('utf-8')
|
data = response.read().decode('utf-8')
|
||||||
|
|
||||||
@ -16,14 +16,12 @@ class Localization(Resource):
|
|||||||
csv_data = csv.DictReader(StringIO(data))
|
csv_data = csv.DictReader(StringIO(data))
|
||||||
|
|
||||||
for language in csv_data.fieldnames[1:]:
|
for language in csv_data.fieldnames[1:]:
|
||||||
localization.append(
|
localization.append({
|
||||||
{
|
|
||||||
'LocalizationName' : language,
|
'LocalizationName' : language,
|
||||||
'LocalizationIndex' : {
|
'LocalizationIndex' : {
|
||||||
'Set' : {}
|
'Set' : {}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
for row in csv_data:
|
for row in csv_data:
|
||||||
localization_string = row['STRING']
|
localization_string = row['STRING']
|
||||||
@ -33,3 +31,29 @@ class Localization(Resource):
|
|||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
return localization, 200
|
return localization, 200
|
||||||
|
|
||||||
|
def get(self, language_tag=None):
|
||||||
|
response = urllib.request.urlopen('https://docs.google.com/spreadsheets/d/e/2PACX-1vRQjCqPvd0Xqcn86WqpFqp_lx4KKpel9O4OV13NycmV8rmqycorgJQm-8qXMfw37QJHun3pqVZFUKG-/pub?gid=0&single=true&output=csv')
|
||||||
|
data = response.read().decode('utf-8')
|
||||||
|
|
||||||
|
csv_data = csv.DictReader(StringIO(data))
|
||||||
|
|
||||||
|
|
||||||
|
if language_tag != None:
|
||||||
|
valid_language_tag = next((l for l in csv_data.fieldnames[1:] if l == language_tag), None)
|
||||||
|
if valid_language_tag is None:
|
||||||
|
valid_language_tag = next((l for l in csv_data.fieldnames[1:] if l.startswith(language_tag[:2])), None)
|
||||||
|
if valid_language_tag is None:
|
||||||
|
valid_language_tag = 'en-US'
|
||||||
|
localization = {
|
||||||
|
'LocalizationName' : valid_language_tag,
|
||||||
|
'LocalizationIndex' : {
|
||||||
|
'Set' : {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for row in csv_data:
|
||||||
|
localization_string = row['STRING']
|
||||||
|
localization['LocalizationIndex']['Set'][localization_string] = row[valid_language_tag]
|
||||||
|
return localization, 200
|
||||||
|
else:
|
||||||
|
return self.list()[0][0], 200
|
||||||
|
@ -12,4 +12,4 @@ api.add_resource(Instance, '/instance/', '/instance/<string:id>')
|
|||||||
api.add_resource(Version, '/version')
|
api.add_resource(Version, '/version')
|
||||||
api.add_resource(Authenticate, '/authenticate')
|
api.add_resource(Authenticate, '/authenticate')
|
||||||
api.add_resource(HistoryGraph, '/history/', '/history/<int:history_count>')
|
api.add_resource(HistoryGraph, '/history/', '/history/<int:history_count>')
|
||||||
api.add_resource(Localization, '/localization')
|
api.add_resource(Localization, '/localization/', '/localization/<string:language_tag>')
|
@ -57,6 +57,8 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
ClientPenalty = Penalty.PenaltyType.Any,
|
ClientPenalty = Penalty.PenaltyType.Any,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DetectionPenaltyResult result = null;
|
||||||
|
|
||||||
if (LastHit == DateTime.MinValue)
|
if (LastHit == DateTime.MinValue)
|
||||||
LastHit = DateTime.UtcNow;
|
LastHit = DateTime.UtcNow;
|
||||||
|
|
||||||
@ -90,7 +92,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Log.WriteDebug($"HitCount = {hitLoc.HitCount}");
|
Log.WriteDebug($"HitCount = {hitLoc.HitCount}");
|
||||||
Log.WriteDebug($"ID = {kill.AttackerId}");
|
Log.WriteDebug($"ID = {kill.AttackerId}");
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = hitLoc.HitOffsetAverage,
|
Value = hitLoc.HitOffsetAverage,
|
||||||
@ -111,7 +113,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Log.WriteDebug($"HitCount = {HitCount}");
|
Log.WriteDebug($"HitCount = {HitCount}");
|
||||||
Log.WriteDebug($"ID = {kill.AttackerId}");
|
Log.WriteDebug($"ID = {kill.AttackerId}");
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = sessAverage,
|
Value = sessAverage,
|
||||||
@ -125,8 +127,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Log.WriteDebug($"PredictVsReal={realAgainstPredict}");
|
Log.WriteDebug($"PredictVsReal={realAgainstPredict}");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
double currentStrain = Strain.GetStrain(isDamage, kill.Damage, kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
|
||||||
double currentWeightedStrain = (currentStrain * ClientStats.SPM) / 170.0;
|
double currentStrain = Strain.GetStrain(isDamage, kill.Damage, kill.Distance / 0.0254, kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset));
|
||||||
|
//double currentWeightedStrain = (currentStrain * ClientStats.SPM) / 170.0;
|
||||||
LastOffset = kill.TimeOffset;
|
LastOffset = kill.TimeOffset;
|
||||||
|
|
||||||
if (currentStrain > ClientStats.MaxStrain)
|
if (currentStrain > ClientStats.MaxStrain)
|
||||||
@ -134,42 +137,25 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
ClientStats.MaxStrain = currentStrain;
|
ClientStats.MaxStrain = currentStrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentWeightedStrain > Thresholds.MaxStrainFlag)
|
|
||||||
{
|
|
||||||
Tracker.OnChange(Strain);
|
|
||||||
|
|
||||||
foreach (string change in Tracker.GetChanges())
|
|
||||||
{
|
|
||||||
Log.WriteDebug(change);
|
|
||||||
}
|
|
||||||
Log.WriteDebug(ClientStats.RoundScore.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Tracker.ClearChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
// flag
|
// flag
|
||||||
if (currentWeightedStrain > Thresholds.MaxStrainFlag)
|
if (currentStrain > Thresholds.MaxStrainFlag)
|
||||||
{
|
{
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||||
Value = currentWeightedStrain,
|
Value = currentStrain,
|
||||||
HitCount = HitCount,
|
HitCount = HitCount,
|
||||||
Type = DetectionType.Strain
|
Type = DetectionType.Strain
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ban
|
// ban
|
||||||
if (currentWeightedStrain > Thresholds.MaxStrainBan
|
if (currentStrain > Thresholds.MaxStrainBan)
|
||||||
&& Kills > Thresholds.LowSampleMinKills)
|
|
||||||
{
|
{
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = currentWeightedStrain,
|
Value = currentStrain,
|
||||||
HitCount = HitCount,
|
HitCount = HitCount,
|
||||||
Type = DetectionType.Strain
|
Type = DetectionType.Strain
|
||||||
};
|
};
|
||||||
@ -217,7 +203,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = currentHeadshotRatio,
|
Value = currentHeadshotRatio,
|
||||||
@ -238,7 +224,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||||
Value = currentHeadshotRatio,
|
Value = currentHeadshotRatio,
|
||||||
@ -267,7 +253,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = currentMaxBoneRatio,
|
Value = currentMaxBoneRatio,
|
||||||
@ -288,7 +274,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||||
Value = currentMaxBoneRatio,
|
Value = currentMaxBoneRatio,
|
||||||
@ -329,7 +315,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
sb.Append($"HitLocation: {kvp.Key} -> {kvp.Value}\r\n");
|
||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Ban,
|
ClientPenalty = Penalty.PenaltyType.Ban,
|
||||||
Value = currentChestAbdomenRatio,
|
Value = currentChestAbdomenRatio,
|
||||||
@ -351,7 +337,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Log.WriteDebug(sb.ToString());
|
Log.WriteDebug(sb.ToString());
|
||||||
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
// Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||||
|
|
||||||
return new DetectionPenaltyResult()
|
result = new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Flag,
|
ClientPenalty = Penalty.PenaltyType.Flag,
|
||||||
Value = currentChestAbdomenRatio,
|
Value = currentChestAbdomenRatio,
|
||||||
@ -364,7 +350,19 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#endregion
|
#endregion
|
||||||
return new DetectionPenaltyResult()
|
|
||||||
|
Tracker.OnChange(new DetectionTracking(ClientStats, kill, Strain));
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
foreach (string change in Tracker.GetChanges())
|
||||||
|
{
|
||||||
|
Log.WriteDebug(change);
|
||||||
|
Log.WriteDebug("--------------SNAPSHOT END-----------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result ?? new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = Penalty.PenaltyType.Any,
|
ClientPenalty = Penalty.PenaltyType.Any,
|
||||||
};
|
};
|
||||||
|
57
Plugins/Stats/Cheat/DetectionTracking.cs
Normal file
57
Plugins/Stats/Cheat/DetectionTracking.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using IW4MAdmin.Plugins.Stats.Cheat;
|
||||||
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||||
|
{
|
||||||
|
class DetectionTracking : ITrackable
|
||||||
|
{
|
||||||
|
EFClientStatistics Stats;
|
||||||
|
EFClientKill Hit;
|
||||||
|
Strain Strain;
|
||||||
|
|
||||||
|
public DetectionTracking(EFClientStatistics stats, EFClientKill hit, Strain strain)
|
||||||
|
{
|
||||||
|
Stats = stats;
|
||||||
|
Hit = hit;
|
||||||
|
Strain = strain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTrackableValue()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine($"SPM = {Stats.SPM}");
|
||||||
|
sb.AppendLine($"KDR = {Stats.KDR}");
|
||||||
|
sb.AppendLine($"Kills = {Stats.Kills}");
|
||||||
|
sb.AppendLine($"Session Score = {Stats.SessionScore}");
|
||||||
|
sb.AppendLine($"Elo = {Stats.EloRating}");
|
||||||
|
sb.AppendLine($"Max Sess Strain = {Stats.MaxSessionStrain}");
|
||||||
|
sb.AppendLine($"MaxStrain = {Stats.MaxStrain}");
|
||||||
|
sb.AppendLine($"Avg Offset = {Stats.AverageHitOffset}");
|
||||||
|
sb.AppendLine($"TimePlayed, {Stats.TimePlayed}");
|
||||||
|
sb.AppendLine($"HitDamage = {Hit.Damage}");
|
||||||
|
sb.AppendLine($"HitOrigin = {Hit.KillOrigin}");
|
||||||
|
sb.AppendLine($"DeathOrigin = {Hit.DeathOrigin}");
|
||||||
|
sb.AppendLine($"ViewAngles = {Hit.ViewAngles}");
|
||||||
|
sb.AppendLine($"WeaponId = {Hit.Weapon.ToString()}");
|
||||||
|
sb.AppendLine($"Timeoffset = {Hit.TimeOffset}");
|
||||||
|
sb.AppendLine($"HitLocation = {Hit.HitLoc.ToString()}");
|
||||||
|
sb.AppendLine($"Distance = {Hit.Distance / 0.0254}");
|
||||||
|
sb.AppendLine($"HitType = {Hit.DeathType.ToString()}");
|
||||||
|
int i = 0;
|
||||||
|
foreach (var predictedAngle in Hit.AnglesList)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"Predicted Angle [{i}] {predictedAngle}");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
sb.AppendLine(Strain.GetTrackableValue());
|
||||||
|
sb.AppendLine($"VictimId = {Hit.VictimId}");
|
||||||
|
sb.AppendLine($"AttackerId = {Hit.AttackerId}");
|
||||||
|
return sb.ToString();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
public int TimesReachedMaxStrain { get; private set; }
|
public int TimesReachedMaxStrain { get; private set; }
|
||||||
|
|
||||||
public double GetStrain(bool isDamage, int damage, Vector3 newAngle, double deltaTime)
|
public double GetStrain(bool isDamage, int damage, double killDistance, Vector3 newAngle, double deltaTime)
|
||||||
{
|
{
|
||||||
if (LastAngle == null)
|
if (LastAngle == null)
|
||||||
LastAngle = newAngle;
|
LastAngle = newAngle;
|
||||||
@ -42,16 +42,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
}
|
}
|
||||||
|
|
||||||
double newStrain = Math.Pow(distance[0] + distance[1], 0.99) / deltaTime;
|
double newStrain = Math.Pow(distance[0] + distance[1], 0.99) / deltaTime;
|
||||||
|
newStrain *= killDistance / 1000.0;
|
||||||
if (damage < 100 && isDamage)
|
|
||||||
{
|
|
||||||
newStrain *= Math.Pow(damage, 2) / 10000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (damage > 100)
|
|
||||||
{
|
|
||||||
newStrain *= damage / 100.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentStrain += newStrain;
|
CurrentStrain += newStrain;
|
||||||
|
|
||||||
@ -64,7 +55,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
public string GetTrackableValue()
|
public string GetTrackableValue()
|
||||||
{
|
{
|
||||||
return $"Strain - {CurrentStrain}, Angle - {LastAngle}, Delta Time - {LastDeltaTime}, Distance - {LastDistance}";
|
return $"Strain = {CurrentStrain}\r\n, Angle = {LastAngle}\r\n, Delta Time = {LastDeltaTime}\r\n, Angle Between = {LastDistance}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private double GetDecay(double deltaTime) => Math.Pow(StrainDecayBase, Math.Pow(2.0, deltaTime / 250.0) / 1000.0);
|
private double GetDecay(double deltaTime) => Math.Pow(StrainDecayBase, Math.Pow(2.0, deltaTime / 250.0) / 1000.0);
|
||||||
|
@ -27,9 +27,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
public const int HighSampleMinKills = 100;
|
public const int HighSampleMinKills = 100;
|
||||||
public const double KillTimeThreshold = 0.2;
|
public const double KillTimeThreshold = 0.2;
|
||||||
|
|
||||||
public const double MaxStrainBan = 2.5;
|
public const double MaxStrainBan = 0.4;
|
||||||
public const double MaxOffset = 1.2;
|
public const double MaxOffset = 1.2;
|
||||||
public const double MaxStrainFlag = 2.0;
|
public const double MaxStrainFlag = 0.36;
|
||||||
|
|
||||||
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
public static double GetMarginOfError(int numKills) => 1.6455 / Math.Sqrt(numKills);
|
||||||
|
|
||||||
|
@ -502,11 +502,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
.Where(cs => cs.Value.ClientId != victimStats.ClientId)
|
.Where(cs => cs.Value.ClientId != victimStats.ClientId)
|
||||||
.Average(cs => cs.Value.EloRating);
|
.Average(cs => cs.Value.EloRating);
|
||||||
|
|
||||||
double attackerEloDifference = Math.Log(attackerLobbyRating) - Math.Log(attackerStats.EloRating);
|
double attackerEloDifference = Math.Log(attackerLobbyRating <= 0 ? 1 : attackerLobbyRating) - Math.Log(attackerStats.EloRating <= 0 ? 1 : attackerStats.EloRating);
|
||||||
double winPercentage = 1.0 / (1 + Math.Pow(10, attackerEloDifference / 0.5));
|
double winPercentage = 1.0 / (1 + Math.Pow(10, attackerEloDifference / Math.E));
|
||||||
|
|
||||||
double victimEloDifference = Math.Log(victimLobbyRating) - Math.Log(victimStats.EloRating);
|
double victimEloDifference = Math.Log(victimLobbyRating <= 0 ? 1 : victimLobbyRating) - Math.Log(victimStats.EloRating <= 0 ? 1 : victimStats.EloRating);
|
||||||
double lossPercentage = 1.0 / (1 + Math.Pow(10, victimEloDifference / 0.5));
|
double lossPercentage = 1.0 / (1 + Math.Pow(10, victimEloDifference / Math.E));
|
||||||
|
|
||||||
attackerStats.EloRating += 24.0 * (1 - winPercentage);
|
attackerStats.EloRating += 24.0 * (1 - winPercentage);
|
||||||
victimStats.EloRating -= 24.0 * winPercentage;
|
victimStats.EloRating -= 24.0 * winPercentage;
|
||||||
@ -559,7 +559,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
// 1.637 is a Eddie-Generated number that weights the KDR nicely
|
// 1.637 is a Eddie-Generated number that weights the KDR nicely
|
||||||
double currentKDR = clientStats.SessionDeaths == 0 ? clientStats.SessionKills : clientStats.SessionKills / clientStats.SessionDeaths;
|
double currentKDR = clientStats.SessionDeaths == 0 ? clientStats.SessionKills : clientStats.SessionKills / clientStats.SessionDeaths;
|
||||||
double alpha = Math.Sqrt(2) / Math.Min(600, clientStats.Kills + clientStats.Deaths);
|
double alpha = Math.Sqrt(2) / Math.Min(600, clientStats.Kills + clientStats.Deaths);
|
||||||
clientStats.RollingWeightedKDR = (alpha * currentKDR) + (1.0 - alpha) * currentKDR;
|
clientStats.RollingWeightedKDR = (alpha * currentKDR) + (1.0 - alpha) * clientStats.KDR;
|
||||||
double KDRWeight = Math.Round(Math.Pow(clientStats.RollingWeightedKDR, 1.637 / Math.E), 3);
|
double KDRWeight = Math.Round(Math.Pow(clientStats.RollingWeightedKDR, 1.637 / Math.E), 3);
|
||||||
|
|
||||||
// calculate the weight of the new play time against last 10 hours of gameplay
|
// calculate the weight of the new play time against last 10 hours of gameplay
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Cheat\Strain.cs~RF16f7b3.TMP" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -16,7 +16,9 @@ namespace SharedLibraryCore.Helpers
|
|||||||
|
|
||||||
public void OnChange(ITrackable value)
|
public void OnChange(ITrackable value)
|
||||||
{
|
{
|
||||||
Values.Add(value.GetTrackableValue());
|
if (Values.Count > 30)
|
||||||
|
Values.RemoveAt(0);
|
||||||
|
Values.Add($"{DateTime.Now.ToString("HH:mm:ss.fff")} {value.GetTrackableValue()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearChanges()
|
public void ClearChanges()
|
||||||
@ -24,18 +26,6 @@ namespace SharedLibraryCore.Helpers
|
|||||||
Values.Clear();
|
Values.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetChanges()
|
public string[] GetChanges() => Values.ToArray();
|
||||||
{
|
|
||||||
List<string> values = new List<string>();
|
|
||||||
|
|
||||||
int number = 1;
|
|
||||||
foreach (string change in Values)
|
|
||||||
{
|
|
||||||
values.Add($"{number} {change}");
|
|
||||||
number++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return values.ToArray();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
version.txt
23
version.txt
@ -1,9 +1,26 @@
|
|||||||
Version 2.1:
|
Version 2.1:
|
||||||
CHANGELOG:
|
CHANGELOG:
|
||||||
-add support for localization
|
-add support for localization (Russian, Spanish, and Portuguese)
|
||||||
-upgraded projects to .NET Core 2.0.7
|
-upgraded projects to .NET Core 2.0.7
|
||||||
-redid the event system to haev a single line of execution
|
-added support for MySQL provider via "ConnectionString" in IW4MAdminSettings.json
|
||||||
-added support for MySQL provider via "ConnectrionString"
|
-refactored some stats code to provide a better representation of player skill as "performance"
|
||||||
|
-added most played command which shows players who have played the most
|
||||||
|
-added unflag command to more intuitively unflag a client
|
||||||
|
-added multi-line tokens: {{TOPSTATS}} {{MOSTPLAYED}}
|
||||||
|
-able to view linked accounts on webfront via dropdown (privileged only)
|
||||||
|
-multiple privileged accouns are consolidated in the admin list
|
||||||
|
-Added IW5m/Pluto IW5, T5m/V2, CoD4, and WaW support
|
||||||
|
-changed event system to use a better pipeline
|
||||||
|
-IW4x anti-cheat further refined
|
||||||
|
-kick and temban required privileges adjusted
|
||||||
|
-fixed issues with RCon responding improperly
|
||||||
|
-improved IW4x frequency of IW4x servers going offline
|
||||||
|
-profanity plugin now kicks players with offensive names (if enabled)
|
||||||
|
-fixed critical bug with CPU usage over time
|
||||||
|
-discord link has been generalized into a "social link" (website/facebook/vk etc...)
|
||||||
|
-untold bug fixes
|
||||||
|
-introduced new bugs to fix in the next version
|
||||||
|
|
||||||
|
|
||||||
Version 2.0:
|
Version 2.0:
|
||||||
CHANGELOG:
|
CHANGELOG:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user