add snap metric to anticheat
update various small code bits
This commit is contained in:
parent
148d28eaca
commit
c18be20899
@ -72,6 +72,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
foreach (var ev in events)
|
foreach (var ev in events)
|
||||||
{
|
{
|
||||||
_server.Manager.GetEventHandler().AddEvent(ev);
|
_server.Manager.GetEventHandler().AddEvent(ev);
|
||||||
|
await ev.WaitAsync(Utilities.DefaultCommandTimeout, ev.Owner.Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
previousFileSize = fileSize;
|
previousFileSize = fileSize;
|
||||||
|
@ -36,14 +36,15 @@ namespace IW4MAdmin.Application.IO
|
|||||||
List<string> logLines = new List<string>();
|
List<string> logLines = new List<string>();
|
||||||
|
|
||||||
// open the file as a stream
|
// open the file as a stream
|
||||||
using (var rd = new StreamReader(new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Utilities.EncodingType))
|
using (FileStream fs = new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
{
|
{
|
||||||
char[] buff = new char[fileSizeDiff];
|
byte[] buff = new byte[fileSizeDiff];
|
||||||
rd.BaseStream.Seek(startPosition, SeekOrigin.Begin);
|
fs.Seek(startPosition, SeekOrigin.Begin);
|
||||||
await rd.ReadAsync(buff, 0, (int)fileSizeDiff);
|
await fs.ReadAsync(buff, 0, (int)fileSizeDiff, server.Manager.CancellationToken);
|
||||||
|
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
foreach (char c in buff)
|
char[] charBuff = Utilities.EncodingType.GetChars(buff);
|
||||||
|
|
||||||
|
foreach (char c in charBuff)
|
||||||
{
|
{
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using IW4MAdmin.Plugins.Stats.Models;
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
@ -18,11 +19,13 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Chest,
|
Chest,
|
||||||
Offset,
|
Offset,
|
||||||
Strain,
|
Strain,
|
||||||
Recoil
|
Recoil,
|
||||||
|
Snap
|
||||||
};
|
};
|
||||||
|
|
||||||
public ChangeTracking<EFACSnapshot> Tracker { get; private set; }
|
public ChangeTracking<EFACSnapshot> Tracker { get; private set; }
|
||||||
public const int MAX_TRACKED_HIT_COUNT = 10;
|
public const int MIN_HITS_TO_RUN_DETECTION = 5;
|
||||||
|
private const int MIN_ANGLE_COUNT = 5;
|
||||||
|
|
||||||
public List<EFClientKill> TrackedHits { get; set; }
|
public List<EFClientKill> TrackedHits { get; set; }
|
||||||
int Kills;
|
int Kills;
|
||||||
@ -36,6 +39,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Strain Strain;
|
Strain Strain;
|
||||||
readonly DateTime ConnectionTime = DateTime.UtcNow;
|
readonly DateTime ConnectionTime = DateTime.UtcNow;
|
||||||
private double sessionAverageRecoilAmount;
|
private double sessionAverageRecoilAmount;
|
||||||
|
private double sessionAverageSnapAmount;
|
||||||
|
private int sessionSnapHits;
|
||||||
|
private EFClientKill lastHit;
|
||||||
|
|
||||||
private class HitInfo
|
private class HitInfo
|
||||||
{
|
{
|
||||||
@ -91,10 +97,57 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
Kills++;
|
Kills++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region VIEWANGLES
|
#region SNAP
|
||||||
if (hit.AnglesList.Count >= 2)
|
if (hit.AnglesList.Count == MIN_ANGLE_COUNT)
|
||||||
{
|
{
|
||||||
double realAgainstPredict = Vector3.ViewAngleDistance(hit.AnglesList[0], hit.AnglesList[1], hit.ViewAngles);
|
if (lastHit == null)
|
||||||
|
{
|
||||||
|
lastHit = hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastHit == hit || lastHit.VictimId != hit.VictimId || (hit.TimeOffset - lastHit.TimeOffset) >= 1000)
|
||||||
|
{
|
||||||
|
ClientStats.SnapHitCount++;
|
||||||
|
sessionSnapHits++;
|
||||||
|
var currentSnapDistance = Vector3.SnapDistance(hit.AnglesList[0], hit.AnglesList[1], hit.ViewAngles);
|
||||||
|
double previousAverage = ClientStats.AverageSnapValue;
|
||||||
|
ClientStats.AverageSnapValue = (previousAverage * (ClientStats.SnapHitCount - 1) + currentSnapDistance) / ClientStats.SnapHitCount;
|
||||||
|
double previousSessionAverage = sessionAverageSnapAmount;
|
||||||
|
sessionAverageSnapAmount = (previousSessionAverage * (sessionSnapHits - 1) + currentSnapDistance) / sessionSnapHits;
|
||||||
|
lastHit = hit;
|
||||||
|
|
||||||
|
if (sessionSnapHits > Thresholds.LowSampleMinKills && sessionAverageSnapAmount > Thresholds.SnapFlagValue)
|
||||||
|
{
|
||||||
|
results.Add(new DetectionPenaltyResult()
|
||||||
|
{
|
||||||
|
ClientPenalty = EFPenalty.PenaltyType.Flag,
|
||||||
|
Value = sessionAverageSnapAmount,
|
||||||
|
HitCount = ClientStats.SnapHitCount,
|
||||||
|
Type = DetectionType.Snap
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionSnapHits > Thresholds.LowSampleMinKills && sessionAverageSnapAmount > Thresholds.SnapBanValue)
|
||||||
|
{
|
||||||
|
results.Add(new DetectionPenaltyResult()
|
||||||
|
{
|
||||||
|
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
||||||
|
Value = sessionAverageSnapAmount,
|
||||||
|
HitCount = ClientStats.SnapHitCount,
|
||||||
|
Type = DetectionType.Snap
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region VIEWANGLES
|
||||||
|
int totalUsableAngleCount = hit.AnglesList.Count - 1;
|
||||||
|
int angleOffsetIndex = totalUsableAngleCount / 2;
|
||||||
|
if (hit.AnglesList.Count == 5)
|
||||||
|
{
|
||||||
|
|
||||||
|
double realAgainstPredict = Vector3.ViewAngleDistance(hit.AnglesList[angleOffsetIndex - 1], hit.AnglesList[angleOffsetIndex + 1], hit.ViewAngles);
|
||||||
|
|
||||||
// LIFETIME
|
// LIFETIME
|
||||||
var hitLoc = ClientStats.HitLocations
|
var hitLoc = ClientStats.HitLocations
|
||||||
@ -119,7 +172,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
results.Add(new DetectionPenaltyResult()
|
results.Add(new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
ClientPenalty = EFPenalty.PenaltyType.Flag,
|
||||||
Value = hitLoc.HitOffsetAverage,
|
Value = hitLoc.HitOffsetAverage,
|
||||||
HitCount = hitLoc.HitCount,
|
HitCount = hitLoc.HitCount,
|
||||||
Type = DetectionType.Offset
|
Type = DetectionType.Offset
|
||||||
@ -146,7 +199,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
|
|
||||||
results.Add(new DetectionPenaltyResult()
|
results.Add(new DetectionPenaltyResult()
|
||||||
{
|
{
|
||||||
ClientPenalty = EFPenalty.PenaltyType.Ban,
|
ClientPenalty = EFPenalty.PenaltyType.Flag,
|
||||||
Value = weightedSessionAverage,
|
Value = weightedSessionAverage,
|
||||||
HitCount = HitCount,
|
HitCount = HitCount,
|
||||||
Type = DetectionType.Offset,
|
Type = DetectionType.Offset,
|
||||||
@ -344,7 +397,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
#endregion
|
#endregion
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
Tracker.OnChange(new EFACSnapshot()
|
var snapshot = new EFACSnapshot()
|
||||||
{
|
{
|
||||||
When = hit.When,
|
When = hit.When,
|
||||||
ClientId = ClientStats.ClientId,
|
ClientId = ClientStats.ClientId,
|
||||||
@ -352,18 +405,16 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
RecoilOffset = hitRecoilAverage,
|
RecoilOffset = hitRecoilAverage,
|
||||||
CurrentSessionLength = (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds,
|
CurrentSessionLength = (int)(DateTime.UtcNow - ConnectionTime).TotalSeconds,
|
||||||
CurrentStrain = currentStrain,
|
CurrentStrain = currentStrain,
|
||||||
CurrentViewAngle = hit.ViewAngles,
|
CurrentViewAngle = new Vector3(hit.ViewAngles.X, hit.ViewAngles.Y, hit.ViewAngles.Z),
|
||||||
Hits = HitCount,
|
Hits = HitCount,
|
||||||
Kills = Kills,
|
Kills = Kills,
|
||||||
Deaths = ClientStats.SessionDeaths,
|
Deaths = ClientStats.SessionDeaths,
|
||||||
HitDestinationId = hit.DeathOrigin.Vector3Id,
|
//todo[9.1.19]: why does this cause unique failure?
|
||||||
HitDestination = hit.DeathOrigin,
|
HitDestination = new Vector3(hit.DeathOrigin.X, hit.DeathOrigin.Y, hit.DeathOrigin.Z),
|
||||||
HitOriginId = hit.KillOrigin.Vector3Id,
|
HitOrigin = new Vector3(hit.KillOrigin.X, hit.KillOrigin.Y, hit.KillOrigin.Z),
|
||||||
HitOrigin = hit.KillOrigin,
|
|
||||||
EloRating = ClientStats.EloRating,
|
EloRating = ClientStats.EloRating,
|
||||||
HitLocation = hit.HitLoc,
|
HitLocation = hit.HitLoc,
|
||||||
LastStrainAngle = Strain.LastAngle,
|
LastStrainAngle = new Vector3(Strain.LastAngle.X, Strain.LastAngle.Y, Strain.LastAngle.Z),
|
||||||
PredictedViewAngles = hit.AnglesList,
|
|
||||||
// this is in "meters"
|
// this is in "meters"
|
||||||
Distance = hit.Distance,
|
Distance = hit.Distance,
|
||||||
SessionScore = ClientStats.SessionScore,
|
SessionScore = ClientStats.SessionScore,
|
||||||
@ -372,7 +423,17 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
|||||||
StrainAngleBetween = Strain.LastDistance,
|
StrainAngleBetween = Strain.LastDistance,
|
||||||
TimeSinceLastEvent = (int)Strain.LastDeltaTime,
|
TimeSinceLastEvent = (int)Strain.LastDeltaTime,
|
||||||
WeaponId = hit.Weapon
|
WeaponId = hit.Weapon
|
||||||
});
|
};
|
||||||
|
|
||||||
|
snapshot.PredictedViewAngles = hit.AnglesList
|
||||||
|
.Select(_angle => new EFACSnapshotVector3()
|
||||||
|
{
|
||||||
|
Vector = _angle,
|
||||||
|
Snapshot = snapshot
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
Tracker.OnChange(snapshot);
|
||||||
|
|
||||||
return results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Ban) ??
|
return results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Ban) ??
|
||||||
results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Flag) ??
|
results.FirstOrDefault(_result => _result.ClientPenalty == EFPenalty.PenaltyType.Flag) ??
|
||||||
|
@ -27,6 +27,8 @@ 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 int LowSampleMinKillsRecoil = 5;
|
public const int LowSampleMinKillsRecoil = 5;
|
||||||
|
public const double SnapFlagValue = 6.12;
|
||||||
|
public const double SnapBanValue = 9.67;
|
||||||
|
|
||||||
public const double MaxStrainBan = 0.9;
|
public const double MaxStrainBan = 0.9;
|
||||||
|
|
||||||
|
@ -44,25 +44,45 @@ namespace IW4MAdmin.Plugins.Stats.Commands
|
|||||||
|
|
||||||
long serverId = StatManager.GetIdForServer(E.Owner);
|
long serverId = StatManager.GetIdForServer(E.Owner);
|
||||||
|
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
|
||||||
{
|
|
||||||
if (E.Target != null)
|
|
||||||
{
|
|
||||||
int performanceRanking = await StatManager.GetClientOverallRanking(E.Target.ClientId);
|
|
||||||
string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
|
|
||||||
|
|
||||||
pStats = (await ctx.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
|
if (E.Target != null)
|
||||||
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
|
{
|
||||||
|
int performanceRanking = await StatManager.GetClientOverallRanking(E.Target.ClientId);
|
||||||
|
string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
|
||||||
|
|
||||||
|
if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Target)))
|
||||||
|
{
|
||||||
|
pStats = Plugin.Manager.GetClientStats(E.Target.ClientId, serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int performanceRanking = await StatManager.GetClientOverallRanking(E.Origin.ClientId);
|
using (var ctx = new DatabaseContext(true))
|
||||||
string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
|
{
|
||||||
|
pStats = (await ctx.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId));
|
||||||
pStats = (await ctx.Set<EFClientStatistics>().FirstAsync((c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId)));
|
}
|
||||||
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
|
|
||||||
}
|
}
|
||||||
|
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int performanceRanking = await StatManager.GetClientOverallRanking(E.Origin.ClientId);
|
||||||
|
string performanceRankingString = performanceRanking == 0 ? loc["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{loc["WEBFRONT_STATS_INDEX_RANKED"]} #{performanceRanking}";
|
||||||
|
|
||||||
|
if (E.Owner.GetClientsAsList().Any(_client => _client.Equals(E.Origin)))
|
||||||
|
{
|
||||||
|
pStats = Plugin.Manager.GetClientStats(E.Origin.ClientId, serverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (var ctx = new DatabaseContext(true))
|
||||||
|
{
|
||||||
|
pStats = (await ctx.Set<EFClientStatistics>().FirstAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()} | {performanceRankingString}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Message.IsBroadcastCommand())
|
if (E.Message.IsBroadcastCommand())
|
||||||
|
@ -117,6 +117,7 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers
|
|||||||
.Include(s => s.HitDestination)
|
.Include(s => s.HitDestination)
|
||||||
.Include(s => s.CurrentViewAngle)
|
.Include(s => s.CurrentViewAngle)
|
||||||
.Include(s => s.PredictedViewAngles)
|
.Include(s => s.PredictedViewAngles)
|
||||||
|
.ThenInclude(_angles => _angles.Vector)
|
||||||
.OrderBy(s => s.When)
|
.OrderBy(s => s.When)
|
||||||
.ThenBy(s => s.Hits);
|
.ThenBy(s => s.Hits);
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using IW4MAdmin.Plugins.Stats.Models;
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Helpers
|
namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||||
@ -9,6 +10,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
class ServerStats {
|
class ServerStats {
|
||||||
public ConcurrentDictionary<int, EFClientStatistics> PlayerStats { get; set; }
|
public ConcurrentDictionary<int, EFClientStatistics> PlayerStats { get; set; }
|
||||||
public ConcurrentDictionary<int, Detection> PlayerDetections { get; set; }
|
public ConcurrentDictionary<int, Detection> PlayerDetections { get; set; }
|
||||||
|
public IList<EFClientKill> HitCache { get; private set; }
|
||||||
public EFServerStatistics ServerStatistics { get; private set; }
|
public EFServerStatistics ServerStatistics { get; private set; }
|
||||||
public EFServer Server { get; private set; }
|
public EFServer Server { get; private set; }
|
||||||
public bool IsTeamBased { get; set; }
|
public bool IsTeamBased { get; set; }
|
||||||
@ -17,6 +19,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
PlayerStats = new ConcurrentDictionary<int, EFClientStatistics>();
|
PlayerStats = new ConcurrentDictionary<int, EFClientStatistics>();
|
||||||
PlayerDetections = new ConcurrentDictionary<int, Detection>();
|
PlayerDetections = new ConcurrentDictionary<int, Detection>();
|
||||||
|
HitCache = new List<EFClientKill>();
|
||||||
ServerStatistics = st;
|
ServerStatistics = st;
|
||||||
Server = sv;
|
Server = sv;
|
||||||
}
|
}
|
||||||
|
@ -19,20 +19,15 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
public class StatManager
|
public class StatManager
|
||||||
{
|
{
|
||||||
|
private const int MAX_CACHED_HITS = 100;
|
||||||
private readonly ConcurrentDictionary<long, ServerStats> _servers;
|
private readonly ConcurrentDictionary<long, ServerStats> _servers;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
private static List<EFServer> serverModels;
|
private static List<EFServer> serverModels;
|
||||||
private readonly SemaphoreSlim OnProcessingPenalty;
|
|
||||||
private readonly SemaphoreSlim OnProcessingSensitive;
|
|
||||||
private readonly List<EFClientKill> _hitCache;
|
|
||||||
|
|
||||||
public StatManager(IManager mgr)
|
public StatManager(IManager mgr)
|
||||||
{
|
{
|
||||||
_servers = new ConcurrentDictionary<long, ServerStats>();
|
_servers = new ConcurrentDictionary<long, ServerStats>();
|
||||||
_hitCache = new List<EFClientKill>();
|
|
||||||
_log = mgr.GetLogger(0);
|
_log = mgr.GetLogger(0);
|
||||||
OnProcessingPenalty = new SemaphoreSlim(1, 1);
|
|
||||||
OnProcessingSensitive = new SemaphoreSlim(1, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupServerIds()
|
private void SetupServerIds()
|
||||||
@ -276,8 +271,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
/// <returns>EFClientStatistic of specified player</returns>
|
/// <returns>EFClientStatistic of specified player</returns>
|
||||||
public async Task<EFClientStatistics> AddPlayer(EFClient pl)
|
public async Task<EFClientStatistics> AddPlayer(EFClient pl)
|
||||||
{
|
{
|
||||||
await OnProcessingSensitive.WaitAsync();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
long serverId = GetIdForServer(pl.CurrentServer);
|
long serverId = GetIdForServer(pl.CurrentServer);
|
||||||
@ -397,11 +390,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
_log.WriteDebug(ex.GetExceptionInfo());
|
_log.WriteDebug(ex.GetExceptionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
OnProcessingSensitive.Release(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,165 +455,144 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
Vector3 vDeathOrigin = null;
|
Vector3 vDeathOrigin = null;
|
||||||
Vector3 vKillOrigin = null;
|
Vector3 vKillOrigin = null;
|
||||||
Vector3 vViewAngles = null;
|
Vector3 vViewAngles = null;
|
||||||
|
SemaphoreSlim waiter = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
vDeathOrigin = Vector3.Parse(deathOrigin);
|
try
|
||||||
vKillOrigin = Vector3.Parse(killOrigin);
|
|
||||||
vViewAngles = Vector3.Parse(viewAngles).FixIW4Angles();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
_log.WriteWarning("Could not parse kill or death origin or viewangle vectors");
|
|
||||||
_log.WriteDebug($"Kill - {killOrigin} Death - {deathOrigin} ViewAngle - {viewAngles}");
|
|
||||||
await AddStandardKill(attacker, victim);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var snapshotAngles = new List<Vector3>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (string angle in snapAngles.Split(':', StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
{
|
||||||
snapshotAngles.Add(Vector3.Parse(angle).FixIW4Angles());
|
vDeathOrigin = Vector3.Parse(deathOrigin);
|
||||||
|
vKillOrigin = Vector3.Parse(killOrigin);
|
||||||
|
vViewAngles = Vector3.Parse(viewAngles).FixIW4Angles();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
_log.WriteWarning("Could not parse snapshot angles");
|
_log.WriteWarning("Could not parse kill or death origin or viewangle vectors");
|
||||||
return;
|
_log.WriteDebug($"Kill - {killOrigin} Death - {deathOrigin} ViewAngle - {viewAngles}");
|
||||||
}
|
await AddStandardKill(attacker, victim);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var hit = new EFClientKill()
|
var snapshotAngles = new List<Vector3>();
|
||||||
{
|
|
||||||
Active = true,
|
|
||||||
AttackerId = attacker.ClientId,
|
|
||||||
VictimId = victim.ClientId,
|
|
||||||
ServerId = serverId,
|
|
||||||
DeathOrigin = vDeathOrigin,
|
|
||||||
KillOrigin = vKillOrigin,
|
|
||||||
DeathType = ParseEnum<IW4Info.MeansOfDeath>.Get(type, typeof(IW4Info.MeansOfDeath)),
|
|
||||||
Damage = int.Parse(damage),
|
|
||||||
HitLoc = ParseEnum<IW4Info.HitLocation>.Get(hitLoc, typeof(IW4Info.HitLocation)),
|
|
||||||
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)),
|
|
||||||
ViewAngles = vViewAngles,
|
|
||||||
TimeOffset = long.Parse(offset),
|
|
||||||
When = time,
|
|
||||||
IsKillstreakKill = isKillstreakKill[0] != '0',
|
|
||||||
AdsPercent = float.Parse(Ads, System.Globalization.CultureInfo.InvariantCulture),
|
|
||||||
Fraction = double.Parse(fraction, System.Globalization.CultureInfo.InvariantCulture),
|
|
||||||
VisibilityPercentage = double.Parse(visibilityPercentage, System.Globalization.CultureInfo.InvariantCulture),
|
|
||||||
IsKill = !isDamage,
|
|
||||||
AnglesList = snapshotAngles
|
|
||||||
};
|
|
||||||
|
|
||||||
if (hit.HitLoc == IW4Info.HitLocation.shield)
|
try
|
||||||
{
|
{
|
||||||
// we don't care about shield hits
|
foreach (string angle in snapAngles.Split(':', StringSplitOptions.RemoveEmptyEntries))
|
||||||
return;
|
{
|
||||||
}
|
snapshotAngles.Add(Vector3.Parse(angle).FixIW4Angles());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDamage)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
await AddStandardKill(attacker, victim);
|
_log.WriteWarning("Could not parse snapshot angles");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// incase the add player event get delayed
|
var hit = new EFClientKill()
|
||||||
if (!_servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
|
{
|
||||||
{
|
Active = true,
|
||||||
await AddPlayer(attacker);
|
AttackerId = attacker.ClientId,
|
||||||
}
|
VictimId = victim.ClientId,
|
||||||
|
ServerId = serverId,
|
||||||
|
DeathOrigin = vDeathOrigin,
|
||||||
|
KillOrigin = vKillOrigin,
|
||||||
|
DeathType = ParseEnum<IW4Info.MeansOfDeath>.Get(type, typeof(IW4Info.MeansOfDeath)),
|
||||||
|
Damage = int.Parse(damage),
|
||||||
|
HitLoc = ParseEnum<IW4Info.HitLocation>.Get(hitLoc, typeof(IW4Info.HitLocation)),
|
||||||
|
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)),
|
||||||
|
ViewAngles = vViewAngles,
|
||||||
|
TimeOffset = long.Parse(offset),
|
||||||
|
When = time,
|
||||||
|
IsKillstreakKill = isKillstreakKill[0] != '0',
|
||||||
|
AdsPercent = float.Parse(Ads, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
Fraction = double.Parse(fraction, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
VisibilityPercentage = double.Parse(visibilityPercentage, System.Globalization.CultureInfo.InvariantCulture),
|
||||||
|
IsKill = !isDamage,
|
||||||
|
AnglesList = snapshotAngles
|
||||||
|
};
|
||||||
|
|
||||||
var clientDetection = _servers[serverId].PlayerDetections[attacker.ClientId];
|
if (hit.HitLoc == IW4Info.HitLocation.shield)
|
||||||
var clientStats = _servers[serverId].PlayerStats[attacker.ClientId];
|
{
|
||||||
|
// we don't care about shield hits
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// increment their hit count
|
// incase the add player event get delayed
|
||||||
if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
if (!_servers[serverId].PlayerStats.ContainsKey(attacker.ClientId))
|
||||||
hit.DeathType == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET ||
|
{
|
||||||
hit.DeathType == IW4Info.MeansOfDeath.MOD_HEAD_SHOT)
|
await AddPlayer(attacker);
|
||||||
{
|
}
|
||||||
clientStats.HitLocations.First(hl => hl.Location == hit.HitLoc).HitCount += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clientStats.SessionKills % Detection.MAX_TRACKED_HIT_COUNT == 0)
|
if (!isDamage)
|
||||||
{
|
{
|
||||||
await OnProcessingPenalty.WaitAsync();
|
await AddStandardKill(attacker, victim);
|
||||||
await SaveClientStats(clientStats);
|
}
|
||||||
OnProcessingPenalty.Release(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hit.IsKillstreakKill)
|
var clientDetection = _servers[serverId].PlayerDetections[attacker.ClientId];
|
||||||
{
|
var clientStats = _servers[serverId].PlayerStats[attacker.ClientId];
|
||||||
return;
|
|
||||||
}
|
waiter = clientStats.ProcessingHit;
|
||||||
|
await waiter.WaitAsync();
|
||||||
|
|
||||||
|
// increment their hit count
|
||||||
|
if (hit.DeathType == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||||
|
hit.DeathType == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET ||
|
||||||
|
hit.DeathType == IW4Info.MeansOfDeath.MOD_HEAD_SHOT)
|
||||||
|
{
|
||||||
|
clientStats.HitLocations.First(hl => hl.Location == hit.HitLoc).HitCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hit.IsKillstreakKill)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Plugin.Config.Configuration().StoreClientKills)
|
if (Plugin.Config.Configuration().StoreClientKills)
|
||||||
{
|
{
|
||||||
await OnProcessingPenalty.WaitAsync();
|
var cache = _servers[serverId].HitCache;
|
||||||
_hitCache.Add(hit);
|
cache.Add(hit);
|
||||||
|
|
||||||
if (_hitCache.Count > Detection.MAX_TRACKED_HIT_COUNT)
|
if (cache.Count > MAX_CACHED_HITS)
|
||||||
{
|
{
|
||||||
|
await SaveHitCache(serverId);
|
||||||
using (var ctx = new DatabaseContext())
|
|
||||||
{
|
|
||||||
ctx.AddRange(_hitCache);
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
_hitCache.Clear();
|
|
||||||
}
|
}
|
||||||
OnProcessingPenalty.Release(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot && attacker.ClientId != victim.ClientId)
|
if (Plugin.Config.Configuration().EnableAntiCheat && !attacker.IsBot && attacker.ClientId != victim.ClientId)
|
||||||
{
|
{
|
||||||
DetectionPenaltyResult result = new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Any };
|
DetectionPenaltyResult result = new DetectionPenaltyResult() { ClientPenalty = EFPenalty.PenaltyType.Any };
|
||||||
await OnProcessingPenalty.WaitAsync();
|
clientDetection.TrackedHits.Add(hit);
|
||||||
|
|
||||||
#if DEBUG
|
if (clientDetection.TrackedHits.Count >= Detection.MIN_HITS_TO_RUN_DETECTION)
|
||||||
if (clientDetection.TrackedHits.Count > 0)
|
|
||||||
#else
|
|
||||||
if (clientDetection.TrackedHits.Count > Detection.MAX_TRACKED_HIT_COUNT)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
while (clientDetection.TrackedHits.Count > 0)
|
while (clientDetection.TrackedHits.Count > 0)
|
||||||
{
|
{
|
||||||
|
var oldestHit = clientDetection.TrackedHits
|
||||||
|
.OrderBy(_hits => _hits.TimeOffset)
|
||||||
|
.First();
|
||||||
|
|
||||||
|
|
||||||
var oldestHit = clientDetection.TrackedHits.OrderBy(_hits => _hits.TimeOffset).First();
|
|
||||||
clientDetection.TrackedHits.Remove(oldestHit);
|
clientDetection.TrackedHits.Remove(oldestHit);
|
||||||
|
|
||||||
result = clientDetection.ProcessHit(oldestHit, isDamage);
|
result = clientDetection.ProcessHit(oldestHit, isDamage);
|
||||||
|
#if !DEBUG
|
||||||
await ApplyPenalty(result, attacker);
|
await ApplyPenalty(result, attacker);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any)
|
if (clientDetection.Tracker.HasChanges && result.ClientPenalty != EFPenalty.PenaltyType.Any)
|
||||||
{
|
{
|
||||||
using (var ctx = new DatabaseContext())
|
await SaveTrackedSnapshots(clientDetection);
|
||||||
{
|
|
||||||
SaveTrackedSnapshots(clientDetection, ctx);
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.ClientPenalty == EFPenalty.PenaltyType.Ban)
|
if (result.ClientPenalty == EFPenalty.PenaltyType.Ban)
|
||||||
{
|
{
|
||||||
|
// we don't care about any additional hits now that they're banned
|
||||||
|
clientDetection.TrackedHits.Clear();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clientDetection.TrackedHits.Add(hit);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnProcessingPenalty.Release(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,11 +600,22 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
_log.WriteError("Could not save hit or AC info");
|
_log.WriteError("Could not save hit or AC info");
|
||||||
_log.WriteDebug(ex.GetExceptionInfo());
|
_log.WriteDebug(ex.GetExceptionInfo());
|
||||||
|
}
|
||||||
|
|
||||||
if (OnProcessingPenalty.CurrentCount == 0)
|
finally
|
||||||
{
|
{
|
||||||
OnProcessingPenalty.Release(1);
|
waiter?.Release(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveHitCache(long serverId)
|
||||||
|
{
|
||||||
|
using (var ctx = new DatabaseContext(true))
|
||||||
|
{
|
||||||
|
var server = _servers[serverId];
|
||||||
|
ctx.AddRange(server.HitCache);
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
server.HitCache.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,59 +657,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTrackedSnapshots(Detection clientDetection, DatabaseContext ctx)
|
async Task SaveTrackedSnapshots(Detection clientDetection)
|
||||||
{
|
{
|
||||||
// todo: why does this cause duplicate primary key
|
|
||||||
_ = clientDetection.Tracker.GetNextChange();
|
|
||||||
EFACSnapshot change;
|
EFACSnapshot change;
|
||||||
while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot))
|
|
||||||
|
using (var ctx = new DatabaseContext(true))
|
||||||
{
|
{
|
||||||
|
while ((change = clientDetection.Tracker.GetNextChange()) != default(EFACSnapshot))
|
||||||
if (change.HitOrigin.Vector3Id > 0)
|
|
||||||
{
|
{
|
||||||
change.HitOriginId = change.HitOrigin.Vector3Id;
|
ctx.Add(change);
|
||||||
ctx.Attach(change.HitOrigin);
|
|
||||||
}
|
}
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
else if (change.HitOrigin.Vector3Id == 0)
|
|
||||||
{
|
|
||||||
ctx.Add(change.HitOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (change.HitDestination.Vector3Id > 0)
|
|
||||||
{
|
|
||||||
change.HitDestinationId = change.HitDestination.Vector3Id;
|
|
||||||
ctx.Attach(change.HitDestination);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (change.HitDestination.Vector3Id == 0)
|
|
||||||
{
|
|
||||||
ctx.Add(change.HitOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (change.CurrentViewAngle.Vector3Id > 0)
|
|
||||||
{
|
|
||||||
change.CurrentViewAngleId = change.CurrentViewAngle.Vector3Id;
|
|
||||||
ctx.Attach(change.CurrentViewAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (change.CurrentViewAngle.Vector3Id == 0)
|
|
||||||
{
|
|
||||||
ctx.Add(change.HitOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (change.LastStrainAngle.Vector3Id > 0)
|
|
||||||
{
|
|
||||||
change.LastStrainAngleId = change.LastStrainAngle.Vector3Id;
|
|
||||||
ctx.Attach(change.LastStrainAngle);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (change.LastStrainAngle.Vector3Id == 0)
|
|
||||||
{
|
|
||||||
ctx.Add(change.HitOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Add(change);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,11 +751,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update their performance
|
// update their performance
|
||||||
#if !DEBUG
|
|
||||||
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 2.5)
|
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 2.5)
|
||||||
#else
|
|
||||||
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 0.1)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
attackerStats.LastStatHistoryUpdate = DateTime.UtcNow;
|
attackerStats.LastStatHistoryUpdate = DateTime.UtcNow;
|
||||||
await UpdateStatHistory(attacker, attackerStats);
|
await UpdateStatHistory(attacker, attackerStats);
|
||||||
@ -837,12 +769,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
int currentSessionTime = (int)(DateTime.UtcNow - client.LastConnection).TotalSeconds;
|
int currentSessionTime = (int)(DateTime.UtcNow - client.LastConnection).TotalSeconds;
|
||||||
|
|
||||||
// don't update their stat history if they haven't played long
|
// don't update their stat history if they haven't played long
|
||||||
//#if DEBUG == false
|
|
||||||
if (currentSessionTime < 60)
|
if (currentSessionTime < 60)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//#endif
|
|
||||||
|
|
||||||
int currentServerTotalPlaytime = clientStats.TimePlayed + currentSessionTime;
|
int currentServerTotalPlaytime = clientStats.TimePlayed + currentSessionTime;
|
||||||
|
|
||||||
@ -1240,9 +1170,18 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
var serverStatsSet = ctx.Set<EFServerStatistics>();
|
var serverStatsSet = ctx.Set<EFServerStatistics>();
|
||||||
serverStatsSet.Update(_servers[serverId].ServerStatistics);
|
serverStatsSet.Update(_servers[serverId].ServerStatistics);
|
||||||
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var client in sv.GetClientsAsList())
|
||||||
|
{
|
||||||
|
var stats = GetClientStats(client.ClientId, serverId);
|
||||||
|
if (stats != null)
|
||||||
|
{
|
||||||
|
await SaveClientStats(stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await SaveHitCache(serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTeamBased(long serverId, bool isTeamBased)
|
public void SetTeamBased(long serverId, bool isTeamBased)
|
||||||
|
@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Models
|
namespace IW4MAdmin.Plugins.Stats.Models
|
||||||
{
|
{
|
||||||
@ -47,6 +48,11 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
public IW4Info.WeaponName WeaponId { get; set; }
|
public IW4Info.WeaponName WeaponId { get; set; }
|
||||||
public IW4Info.HitLocation HitLocation { get; set; }
|
public IW4Info.HitLocation HitLocation { get; set; }
|
||||||
public IW4Info.MeansOfDeath HitType { get; set; }
|
public IW4Info.MeansOfDeath HitType { get; set; }
|
||||||
public virtual ICollection<Vector3> PredictedViewAngles { get; set; }
|
public virtual ICollection<EFACSnapshotVector3> PredictedViewAngles { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string CapturedViewAngles => PredictedViewAngles?.Count > 0 ?
|
||||||
|
string.Join(", ", PredictedViewAngles.OrderBy(_angle => _angle.ACSnapshotVector3Id).Select(_angle => _angle.Vector.ToString())) :
|
||||||
|
"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
Plugins/Stats/Models/EFACSnapshotVector3.cs
Normal file
26
Plugins/Stats/Models/EFACSnapshotVector3.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
using SharedLibraryCore.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Plugins.Stats.Models
|
||||||
|
{
|
||||||
|
public class EFACSnapshotVector3
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int ACSnapshotVector3Id { get; set; }
|
||||||
|
|
||||||
|
public int SnapshotId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("SnapshotId")]
|
||||||
|
public EFACSnapshot Snapshot { get; set; }
|
||||||
|
|
||||||
|
public int Vector3Id { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("Vector3Id")]
|
||||||
|
public Vector3 Vector { get; set;}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
@ -12,6 +13,16 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
{
|
{
|
||||||
public class EFClientStatistics : SharedEntity
|
public class EFClientStatistics : SharedEntity
|
||||||
{
|
{
|
||||||
|
public EFClientStatistics()
|
||||||
|
{
|
||||||
|
ProcessingHit = new SemaphoreSlim(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
~EFClientStatistics()
|
||||||
|
{
|
||||||
|
ProcessingHit.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public int ClientId { get; set; }
|
public int ClientId { get; set; }
|
||||||
[ForeignKey("ClientId")]
|
[ForeignKey("ClientId")]
|
||||||
public virtual EFClient Client { get; set; }
|
public virtual EFClient Client { get; set; }
|
||||||
@ -27,6 +38,8 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
public double RollingWeightedKDR { get; set; }
|
public double RollingWeightedKDR { get; set; }
|
||||||
public double VisionAverage { get; set; }
|
public double VisionAverage { get; set; }
|
||||||
public double AverageRecoilOffset { get; set; }
|
public double AverageRecoilOffset { get; set; }
|
||||||
|
public double AverageSnapValue { get; set; }
|
||||||
|
public int SnapHitCount { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public double Performance
|
public double Performance
|
||||||
{
|
{
|
||||||
@ -96,12 +109,14 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
private List<int> SessionScores = new List<int>() { 0 };
|
private readonly List<int> SessionScores = new List<int>() { 0 };
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public IW4Info.Team Team { get; set; }
|
public IW4Info.Team Team { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public DateTime LastStatHistoryUpdate { get; set; } = DateTime.UtcNow;
|
public DateTime LastStatHistoryUpdate { get; set; } = DateTime.UtcNow;
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public double SessionSPM { get; set; }
|
public double SessionSPM { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public SemaphoreSlim ProcessingHit { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,10 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
public static StatManager Manager { get; private set; }
|
public static StatManager Manager { get; private set; }
|
||||||
public static IManager ServerManager;
|
public static IManager ServerManager;
|
||||||
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
public static BaseConfigurationHandler<StatsConfiguration> Config { get; private set; }
|
||||||
|
#if DEBUG
|
||||||
|
int scriptDamageCount;
|
||||||
|
int scriptKillCount;
|
||||||
|
#endif
|
||||||
|
|
||||||
public async Task OnEventAsync(GameEvent E, Server S)
|
public async Task OnEventAsync(GameEvent E, Server S)
|
||||||
{
|
{
|
||||||
@ -44,7 +48,6 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Disconnect:
|
case GameEvent.EventType.Disconnect:
|
||||||
await Manager.RemovePlayer(E.Origin);
|
await Manager.RemovePlayer(E.Origin);
|
||||||
await Manager.Sync(S);
|
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Say:
|
case GameEvent.EventType.Say:
|
||||||
if (!string.IsNullOrEmpty(E.Data) &&
|
if (!string.IsNullOrEmpty(E.Data) &&
|
||||||
@ -56,8 +59,10 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
case GameEvent.EventType.MapChange:
|
case GameEvent.EventType.MapChange:
|
||||||
Manager.SetTeamBased(StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
|
Manager.SetTeamBased(StatManager.GetIdForServer(E.Owner), E.Owner.Gametype != "dm");
|
||||||
Manager.ResetKillstreaks(StatManager.GetIdForServer(E.Owner));
|
Manager.ResetKillstreaks(StatManager.GetIdForServer(E.Owner));
|
||||||
|
await Manager.Sync(E.Owner);
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.MapEnd:
|
case GameEvent.EventType.MapEnd:
|
||||||
|
await Manager.Sync(E.Owner);
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.JoinTeam:
|
case GameEvent.EventType.JoinTeam:
|
||||||
break;
|
break;
|
||||||
@ -85,8 +90,17 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
E.Origin = E.Target;
|
E.Origin = E.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
scriptKillCount++;
|
||||||
|
S.Logger.WriteInfo($"Start ScriptKill {scriptKillCount}");
|
||||||
|
#endif
|
||||||
|
|
||||||
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
S.Logger.WriteInfo($"End ScriptKill {scriptKillCount}");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GameEvent.EventType.Kill:
|
case GameEvent.EventType.Kill:
|
||||||
@ -123,8 +137,21 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
E.Origin = E.Target;
|
E.Origin = E.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
scriptDamageCount++;
|
||||||
|
S.Logger.WriteInfo($"Start ScriptDamage {scriptDamageCount}");
|
||||||
|
#endif
|
||||||
|
|
||||||
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, StatManager.GetIdForServer(E.Owner), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13], killInfo[14], killInfo[15]);
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
S.Logger.WriteInfo($"End ScriptDamage {scriptDamageCount}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -245,6 +272,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
double chestAbdomenRatio = 0;
|
double chestAbdomenRatio = 0;
|
||||||
double hitOffsetAverage = 0;
|
double hitOffsetAverage = 0;
|
||||||
double averageRecoilAmount = 0;
|
double averageRecoilAmount = 0;
|
||||||
|
double averageSnapValue = 0;
|
||||||
double maxStrain = clientStats.Count(c => c.MaxStrain > 0) == 0 ? 0 : clientStats.Max(cs => cs.MaxStrain);
|
double maxStrain = clientStats.Count(c => c.MaxStrain > 0) == 0 ? 0 : clientStats.Max(cs => cs.MaxStrain);
|
||||||
|
|
||||||
if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
|
if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
|
||||||
@ -268,6 +296,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations);
|
var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations);
|
||||||
hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount);
|
hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount);
|
||||||
averageRecoilAmount = clientStats.Average(_stat => _stat.AverageRecoilOffset);
|
averageRecoilAmount = clientStats.Average(_stat => _stat.AverageRecoilOffset);
|
||||||
|
averageSnapValue = clientStats.Any(_stats => _stats.AverageSnapValue > 0) ? clientStats.Where(_stats => _stats.AverageSnapValue > 0).Average(_stat => _stat.AverageSnapValue) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<ProfileMeta>()
|
return new List<ProfileMeta>()
|
||||||
@ -343,6 +372,16 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM7"],
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM7"],
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
|
new ProfileMeta()
|
||||||
|
{
|
||||||
|
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 8",
|
||||||
|
Value = Math.Round(averageSnapValue, 3).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
|
||||||
|
Type = ProfileMeta.MetaType.Information,
|
||||||
|
Column = 2,
|
||||||
|
Order = 6,
|
||||||
|
Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM8"],
|
||||||
|
Sensitive = true
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +522,7 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private bool ShouldIgnoreEvent(EFClient origin, EFClient target)
|
private bool ShouldIgnoreEvent(EFClient origin, EFClient target)
|
||||||
{
|
{
|
||||||
return ((origin?.NetworkId <= 1 && target?.NetworkId <= 1) || (origin?.ClientId <=1 && target?.ClientId <= 1));
|
return ((origin?.NetworkId <= 1 && target?.NetworkId <= 1) || (origin?.ClientId <= 1 && target?.ClientId <= 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -13,11 +13,11 @@
|
|||||||
<!-- this is another ugly hack-->
|
<!-- this is another ugly hack-->
|
||||||
@if (prop.GetValue(snapshot) is System.Collections.Generic.HashSet<SharedLibraryCore.Helpers.Vector3>)
|
@if (prop.GetValue(snapshot) is System.Collections.Generic.HashSet<SharedLibraryCore.Helpers.Vector3>)
|
||||||
{
|
{
|
||||||
<span class="text-white">@prop.Name </span>
|
@*<span class="text-white">@prop.Name </span>
|
||||||
foreach (var v in (System.Collections.Generic.HashSet<SharedLibraryCore.Helpers.Vector3>)prop.GetValue(snapshot))
|
foreach (var v in (System.Collections.Generic.HashSet<SharedLibraryCore.Helpers.Vector3>)prop.GetValue(snapshot))
|
||||||
{
|
{
|
||||||
<span>@v.ToString(),</span><br />
|
<span>@v.ToString(),</span><br />
|
||||||
}
|
}*@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ namespace SharedLibraryCore.Helpers
|
|||||||
[Key]
|
[Key]
|
||||||
public int Vector3Id { get; set; }
|
public int Vector3Id { get; set; }
|
||||||
public float X { get; protected set; }
|
public float X { get; protected set; }
|
||||||
public float Y { get; protected set; }
|
public float Y { get; protected set; }
|
||||||
public float Z { get; protected set; }
|
public float Z { get; protected set; }
|
||||||
|
|
||||||
// this is for EF and really should be somewhere else
|
// this is for EF and really should be somewhere else
|
||||||
@ -57,7 +57,7 @@ namespace SharedLibraryCore.Helpers
|
|||||||
|
|
||||||
public static double AbsoluteDistance(Vector3 a, Vector3 b)
|
public static double AbsoluteDistance(Vector3 a, Vector3 b)
|
||||||
{
|
{
|
||||||
double deltaX = Math.Abs(b.X -a.X);
|
double deltaX = Math.Abs(b.X - a.X);
|
||||||
double deltaY = Math.Abs(b.Y - a.Y);
|
double deltaY = Math.Abs(b.Y - a.Y);
|
||||||
|
|
||||||
// this 'fixes' the roll-over angles
|
// this 'fixes' the roll-over angles
|
||||||
@ -67,6 +67,43 @@ namespace SharedLibraryCore.Helpers
|
|||||||
return Math.Sqrt((dx * dx) + (dy * dy));
|
return Math.Sqrt((dx * dx) + (dy * dy));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double SnapDistance(Vector3 a, Vector3 b, Vector3 c)
|
||||||
|
{
|
||||||
|
a = a.FixIW4Angles();
|
||||||
|
b = b.FixIW4Angles();
|
||||||
|
c = c.FixIW4Angles();
|
||||||
|
|
||||||
|
float preserveDirectionAngle(float a1, float b1)
|
||||||
|
{
|
||||||
|
float difference = b1 - a1;
|
||||||
|
while (difference < -180) difference += 360;
|
||||||
|
while (difference > 180) difference -= 360;
|
||||||
|
return difference;
|
||||||
|
}
|
||||||
|
|
||||||
|
var directions = new[]
|
||||||
|
{
|
||||||
|
new Vector3()
|
||||||
|
{
|
||||||
|
X = preserveDirectionAngle(b.X, a.X),
|
||||||
|
Y = preserveDirectionAngle(b.Y, a.Y)
|
||||||
|
},
|
||||||
|
new Vector3()
|
||||||
|
{
|
||||||
|
X = preserveDirectionAngle(c.X, b.X),
|
||||||
|
Y = preserveDirectionAngle(c.Y, b.Y)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var distance = new Vector3
|
||||||
|
{
|
||||||
|
X = Math.Abs(directions[1].X - directions[0].X),
|
||||||
|
Y = Math.Abs(directions[1].Y - directions[0].Y)
|
||||||
|
};
|
||||||
|
|
||||||
|
return Math.Sqrt((distance.X * distance.X) + (distance.Y * distance.Y));
|
||||||
|
}
|
||||||
|
|
||||||
public static double ViewAngleDistance(Vector3 a, Vector3 b, Vector3 c)
|
public static double ViewAngleDistance(Vector3 a, Vector3 b, Vector3 c)
|
||||||
{
|
{
|
||||||
double dabX = Math.Abs(a.X - b.X);
|
double dabX = Math.Abs(a.X - b.X);
|
||||||
|
706
SharedLibraryCore/Migrations/20190831210503_AvgSnapValueToClientStatistics.Designer.cs
generated
Normal file
706
SharedLibraryCore/Migrations/20190831210503_AvgSnapValueToClientStatistics.Designer.cs
generated
Normal file
@ -0,0 +1,706 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20190831210503_AvgSnapValueToClientStatistics")]
|
||||||
|
partial class AvgSnapValueToClientStatistics
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentSessionLength");
|
||||||
|
|
||||||
|
b.Property<double>("CurrentStrain");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("Distance");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("HitDestinationId");
|
||||||
|
|
||||||
|
b.Property<int>("HitLocation");
|
||||||
|
|
||||||
|
b.Property<int>("HitOriginId");
|
||||||
|
|
||||||
|
b.Property<int>("HitType");
|
||||||
|
|
||||||
|
b.Property<int>("Hits");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<int>("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.Property<double>("RecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAngleOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionSPM");
|
||||||
|
|
||||||
|
b.Property<int>("SessionScore");
|
||||||
|
|
||||||
|
b.Property<double>("StrainAngleBetween");
|
||||||
|
|
||||||
|
b.Property<int>("TimeSinceLastEvent");
|
||||||
|
|
||||||
|
b.Property<int>("WeaponId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.HasIndex("HitDestinationId");
|
||||||
|
|
||||||
|
b.HasIndex("HitOriginId");
|
||||||
|
|
||||||
|
b.HasIndex("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshot");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId");
|
||||||
|
|
||||||
|
b.Property<int>("Damage");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType");
|
||||||
|
|
||||||
|
b.Property<double>("Fraction");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc");
|
||||||
|
|
||||||
|
b.Property<bool>("IsKill");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Map");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("TimeSent");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.HasKey("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientRatingHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<double>("AverageRecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("AverageSnapValue");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR");
|
||||||
|
|
||||||
|
b.Property<double>("SPM");
|
||||||
|
|
||||||
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
|
b.Property<double>("VisionAverage");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnName("EFClientStatistics_ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage");
|
||||||
|
|
||||||
|
b.Property<int>("Location");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnName("EFClientStatistics_ServerId");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityAmount");
|
||||||
|
|
||||||
|
b.Property<bool>("Newest");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.Property<int>("RatingHistoryId");
|
||||||
|
|
||||||
|
b.Property<long?>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("Performance", "Ranking", "When");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("EndPoint");
|
||||||
|
|
||||||
|
b.Property<int?>("GameName");
|
||||||
|
|
||||||
|
b.Property<int>("Port");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("IPAddress");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.Property<string>("SearchableName")
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("Name");
|
||||||
|
|
||||||
|
b.HasIndex("SearchableName");
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ChangeHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasMaxLength(128);
|
||||||
|
|
||||||
|
b.Property<string>("CurrentValue");
|
||||||
|
|
||||||
|
b.Property<int>("OriginEntityId");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousValue");
|
||||||
|
|
||||||
|
b.Property<int>("TargetEntityId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeChanged");
|
||||||
|
|
||||||
|
b.Property<int>("TypeOfChange");
|
||||||
|
|
||||||
|
b.HasKey("ChangeHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFChangeHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId");
|
||||||
|
|
||||||
|
b.Property<int>("Connections");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection");
|
||||||
|
|
||||||
|
b.Property<int>("Level");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId");
|
||||||
|
|
||||||
|
b.Property<string>("Password");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MetaId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created");
|
||||||
|
|
||||||
|
b.Property<string>("Extra");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32);
|
||||||
|
|
||||||
|
b.Property<DateTime>("Updated");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("MetaId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("Key");
|
||||||
|
|
||||||
|
b.ToTable("EFMeta");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Expires");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEvadedOffense");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int?>("EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
b.Property<float>("X");
|
||||||
|
|
||||||
|
b.Property<float>("Y");
|
||||||
|
|
||||||
|
b.Property<float>("Z");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
b.ToTable("Vector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentViewAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitDestinationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitOriginId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LastStrainAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("ClientId", "ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||||
|
.WithMany("Ratings")
|
||||||
|
.HasForeignKey("RatingHistoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany("Meta")
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("EFACSnapshotSnapshotId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
public partial class AvgSnapValueToClientStatistics : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "AverageSnapValue",
|
||||||
|
table: "EFClientStatistics",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AverageSnapValue",
|
||||||
|
table: "EFClientStatistics");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
708
SharedLibraryCore/Migrations/20190901180209_AddSnapHitCountToClientStatistics.Designer.cs
generated
Normal file
708
SharedLibraryCore/Migrations/20190901180209_AddSnapHitCountToClientStatistics.Designer.cs
generated
Normal file
@ -0,0 +1,708 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20190901180209_AddSnapHitCountToClientStatistics")]
|
||||||
|
partial class AddSnapHitCountToClientStatistics
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentSessionLength");
|
||||||
|
|
||||||
|
b.Property<double>("CurrentStrain");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("Distance");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("HitDestinationId");
|
||||||
|
|
||||||
|
b.Property<int>("HitLocation");
|
||||||
|
|
||||||
|
b.Property<int>("HitOriginId");
|
||||||
|
|
||||||
|
b.Property<int>("HitType");
|
||||||
|
|
||||||
|
b.Property<int>("Hits");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<int>("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.Property<double>("RecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAngleOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionSPM");
|
||||||
|
|
||||||
|
b.Property<int>("SessionScore");
|
||||||
|
|
||||||
|
b.Property<double>("StrainAngleBetween");
|
||||||
|
|
||||||
|
b.Property<int>("TimeSinceLastEvent");
|
||||||
|
|
||||||
|
b.Property<int>("WeaponId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.HasIndex("HitDestinationId");
|
||||||
|
|
||||||
|
b.HasIndex("HitOriginId");
|
||||||
|
|
||||||
|
b.HasIndex("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshot");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId");
|
||||||
|
|
||||||
|
b.Property<int>("Damage");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType");
|
||||||
|
|
||||||
|
b.Property<double>("Fraction");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc");
|
||||||
|
|
||||||
|
b.Property<bool>("IsKill");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Map");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("TimeSent");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.HasKey("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientRatingHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<double>("AverageRecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("AverageSnapValue");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR");
|
||||||
|
|
||||||
|
b.Property<double>("SPM");
|
||||||
|
|
||||||
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("SnapHitCount");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
|
b.Property<double>("VisionAverage");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnName("EFClientStatistics_ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage");
|
||||||
|
|
||||||
|
b.Property<int>("Location");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnName("EFClientStatistics_ServerId");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityAmount");
|
||||||
|
|
||||||
|
b.Property<bool>("Newest");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.Property<int>("RatingHistoryId");
|
||||||
|
|
||||||
|
b.Property<long?>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("Performance", "Ranking", "When");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("EndPoint");
|
||||||
|
|
||||||
|
b.Property<int?>("GameName");
|
||||||
|
|
||||||
|
b.Property<int>("Port");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("IPAddress");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.Property<string>("SearchableName")
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("Name");
|
||||||
|
|
||||||
|
b.HasIndex("SearchableName");
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ChangeHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasMaxLength(128);
|
||||||
|
|
||||||
|
b.Property<string>("CurrentValue");
|
||||||
|
|
||||||
|
b.Property<int>("OriginEntityId");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousValue");
|
||||||
|
|
||||||
|
b.Property<int>("TargetEntityId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeChanged");
|
||||||
|
|
||||||
|
b.Property<int>("TypeOfChange");
|
||||||
|
|
||||||
|
b.HasKey("ChangeHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFChangeHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId");
|
||||||
|
|
||||||
|
b.Property<int>("Connections");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection");
|
||||||
|
|
||||||
|
b.Property<int>("Level");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId");
|
||||||
|
|
||||||
|
b.Property<string>("Password");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MetaId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created");
|
||||||
|
|
||||||
|
b.Property<string>("Extra");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32);
|
||||||
|
|
||||||
|
b.Property<DateTime>("Updated");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("MetaId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("Key");
|
||||||
|
|
||||||
|
b.ToTable("EFMeta");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Expires");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEvadedOffense");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int?>("EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
b.Property<float>("X");
|
||||||
|
|
||||||
|
b.Property<float>("Y");
|
||||||
|
|
||||||
|
b.Property<float>("Z");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
b.ToTable("Vector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentViewAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitDestinationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitOriginId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LastStrainAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("ClientId", "ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||||
|
.WithMany("Ratings")
|
||||||
|
.HasForeignKey("RatingHistoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany("Meta")
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("EFACSnapshotSnapshotId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddSnapHitCountToClientStatistics : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "SnapHitCount",
|
||||||
|
table: "EFClientStatistics",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SnapHitCount",
|
||||||
|
table: "EFClientStatistics");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
728
SharedLibraryCore/Migrations/20190901223620_UseJunctionTableForSnapshotVector3.Designer.cs
generated
Normal file
728
SharedLibraryCore/Migrations/20190901223620_UseJunctionTableForSnapshotVector3.Designer.cs
generated
Normal file
@ -0,0 +1,728 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20190901223620_UseJunctionTableForSnapshotVector3")]
|
||||||
|
partial class UseJunctionTableForSnapshotVector3
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("SnapshotId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentSessionLength");
|
||||||
|
|
||||||
|
b.Property<double>("CurrentStrain");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("Distance");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("HitDestinationId");
|
||||||
|
|
||||||
|
b.Property<int>("HitLocation");
|
||||||
|
|
||||||
|
b.Property<int>("HitOriginId");
|
||||||
|
|
||||||
|
b.Property<int>("HitType");
|
||||||
|
|
||||||
|
b.Property<int>("Hits");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<int>("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.Property<double>("RecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionAngleOffset");
|
||||||
|
|
||||||
|
b.Property<double>("SessionSPM");
|
||||||
|
|
||||||
|
b.Property<int>("SessionScore");
|
||||||
|
|
||||||
|
b.Property<double>("StrainAngleBetween");
|
||||||
|
|
||||||
|
b.Property<int>("TimeSinceLastEvent");
|
||||||
|
|
||||||
|
b.Property<int>("WeaponId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentViewAngleId");
|
||||||
|
|
||||||
|
b.HasIndex("HitDestinationId");
|
||||||
|
|
||||||
|
b.HasIndex("HitOriginId");
|
||||||
|
|
||||||
|
b.HasIndex("LastStrainAngleId");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshot");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ACSnapshotVector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("SnapshotId");
|
||||||
|
|
||||||
|
b.Property<int>("Vector3Id");
|
||||||
|
|
||||||
|
b.HasKey("ACSnapshotVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshotVector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId");
|
||||||
|
|
||||||
|
b.Property<int>("Damage");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType");
|
||||||
|
|
||||||
|
b.Property<double>("Fraction");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc");
|
||||||
|
|
||||||
|
b.Property<bool>("IsKill");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Map");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<double>("VisibilityPercentage");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("TimeSent");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.HasKey("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientRatingHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<double>("AverageRecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("AverageSnapValue");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR");
|
||||||
|
|
||||||
|
b.Property<double>("SPM");
|
||||||
|
|
||||||
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("SnapHitCount");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
|
b.Property<double>("VisionAverage");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnName("EFClientStatistics_ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage");
|
||||||
|
|
||||||
|
b.Property<int>("Location");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId")
|
||||||
|
.HasColumnName("EFClientStatistics_ServerId");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ActivityAmount");
|
||||||
|
|
||||||
|
b.Property<bool>("Newest");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.Property<int>("RatingHistoryId");
|
||||||
|
|
||||||
|
b.Property<long?>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("RatingHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("Performance", "Ranking", "When");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("EndPoint");
|
||||||
|
|
||||||
|
b.Property<int?>("GameName");
|
||||||
|
|
||||||
|
b.Property<int>("Port");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<long>("ServerId");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("IPAddress");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.Property<string>("SearchableName")
|
||||||
|
.HasMaxLength(24);
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("Name");
|
||||||
|
|
||||||
|
b.HasIndex("SearchableName");
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ChangeHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("Comment")
|
||||||
|
.HasMaxLength(128);
|
||||||
|
|
||||||
|
b.Property<string>("CurrentValue");
|
||||||
|
|
||||||
|
b.Property<int>("OriginEntityId");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousValue");
|
||||||
|
|
||||||
|
b.Property<int>("TargetEntityId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeChanged");
|
||||||
|
|
||||||
|
b.Property<int>("TypeOfChange");
|
||||||
|
|
||||||
|
b.HasKey("ChangeHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFChangeHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId");
|
||||||
|
|
||||||
|
b.Property<int>("Connections");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection");
|
||||||
|
|
||||||
|
b.Property<int>("Level");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId");
|
||||||
|
|
||||||
|
b.Property<string>("Password");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("MetaId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Created");
|
||||||
|
|
||||||
|
b.Property<string>("Extra");
|
||||||
|
|
||||||
|
b.Property<string>("Key")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(32);
|
||||||
|
|
||||||
|
b.Property<DateTime>("Updated");
|
||||||
|
|
||||||
|
b.Property<string>("Value")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("MetaId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("Key");
|
||||||
|
|
||||||
|
b.ToTable("EFMeta");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("Expires");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEvadedOffense");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<float>("X");
|
||||||
|
|
||||||
|
b.Property<float>("Y");
|
||||||
|
|
||||||
|
b.Property<float>("Z");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("Vector3");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentViewAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitDestinationId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("HitOriginId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("LastStrainAngleId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("SnapshotId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Vector3Id")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("ClientId", "ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
|
||||||
|
.WithMany("Ratings")
|
||||||
|
.HasForeignKey("RatingHistoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany("Meta")
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
public partial class UseJunctionTableForSnapshotVector3 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
if (migrationBuilder.ActiveProvider != "Microsoft.EntityFrameworkCore.Sqlite")
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Vector3_EFACSnapshot_EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Vector3_EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3");
|
||||||
|
}
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "EFACSnapshotVector3",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ACSnapshotVector3Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
SnapshotId = table.Column<int>(nullable: false),
|
||||||
|
Vector3Id = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_EFACSnapshotVector3", x => x.ACSnapshotVector3Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_EFACSnapshotVector3_EFACSnapshot_SnapshotId",
|
||||||
|
column: x => x.SnapshotId,
|
||||||
|
principalTable: "EFACSnapshot",
|
||||||
|
principalColumn: "SnapshotId",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_EFACSnapshotVector3_Vector3_Vector3Id",
|
||||||
|
column: x => x.Vector3Id,
|
||||||
|
principalTable: "Vector3",
|
||||||
|
principalColumn: "Vector3Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_EFACSnapshotVector3_SnapshotId",
|
||||||
|
table: "EFACSnapshotVector3",
|
||||||
|
column: "SnapshotId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_EFACSnapshotVector3_Vector3Id",
|
||||||
|
table: "EFACSnapshotVector3",
|
||||||
|
column: "Vector3Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "EFACSnapshotVector3");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Vector3_EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3",
|
||||||
|
column: "EFACSnapshotSnapshotId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Vector3_EFACSnapshot_EFACSnapshotSnapshotId",
|
||||||
|
table: "Vector3",
|
||||||
|
column: "EFACSnapshotSnapshotId",
|
||||||
|
principalTable: "EFACSnapshot",
|
||||||
|
principalColumn: "SnapshotId",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -82,6 +82,24 @@ namespace SharedLibraryCore.Migrations
|
|||||||
b.ToTable("EFACSnapshot");
|
b.ToTable("EFACSnapshot");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ACSnapshotVector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("SnapshotId");
|
||||||
|
|
||||||
|
b.Property<int>("Vector3Id");
|
||||||
|
|
||||||
|
b.HasKey("ACSnapshotVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("SnapshotId");
|
||||||
|
|
||||||
|
b.HasIndex("Vector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFACSnapshotVector3");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("KillId")
|
b.Property<long>("KillId")
|
||||||
@ -188,6 +206,8 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.Property<double>("AverageRecoilOffset");
|
b.Property<double>("AverageRecoilOffset");
|
||||||
|
|
||||||
|
b.Property<double>("AverageSnapValue");
|
||||||
|
|
||||||
b.Property<int>("Deaths");
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
b.Property<double>("EloRating");
|
b.Property<double>("EloRating");
|
||||||
@ -202,6 +222,8 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.Property<double>("Skill");
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("SnapHitCount");
|
||||||
|
|
||||||
b.Property<int>("TimePlayed");
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
b.Property<double>("VisionAverage");
|
b.Property<double>("VisionAverage");
|
||||||
@ -498,8 +520,6 @@ namespace SharedLibraryCore.Migrations
|
|||||||
b.Property<int>("Vector3Id")
|
b.Property<int>("Vector3Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
b.Property<int?>("EFACSnapshotSnapshotId");
|
|
||||||
|
|
||||||
b.Property<float>("X");
|
b.Property<float>("X");
|
||||||
|
|
||||||
b.Property<float>("Y");
|
b.Property<float>("Y");
|
||||||
@ -508,8 +528,6 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.HasKey("Vector3Id");
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
b.HasIndex("EFACSnapshotSnapshotId");
|
|
||||||
|
|
||||||
b.ToTable("Vector3");
|
b.ToTable("Vector3");
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -541,6 +559,19 @@ namespace SharedLibraryCore.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
|
||||||
|
.WithMany("PredictedViewAngles")
|
||||||
|
.HasForeignKey("SnapshotId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("Vector3Id")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
@ -689,13 +720,6 @@ namespace SharedLibraryCore.Migrations
|
|||||||
.HasForeignKey("PunisherId")
|
.HasForeignKey("PunisherId")
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot")
|
|
||||||
.WithMany("PredictedViewAngles")
|
|
||||||
.HasForeignKey("EFACSnapshotSnapshotId");
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
#pragma warning restore 612, 618
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,13 @@ namespace SharedLibraryCore.RCon
|
|||||||
{
|
{
|
||||||
class ConnectionState
|
class ConnectionState
|
||||||
{
|
{
|
||||||
|
~ConnectionState()
|
||||||
|
{
|
||||||
|
OnComplete.Dispose();
|
||||||
|
OnSentData.Dispose();
|
||||||
|
OnReceivedData.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
public int ConnectionAttempts { get; set; }
|
public int ConnectionAttempts { get; set; }
|
||||||
const int BufferSize = 4096;
|
const int BufferSize = 4096;
|
||||||
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
|
public readonly byte[] ReceiveBuffer = new byte[BufferSize];
|
||||||
@ -152,7 +159,6 @@ namespace SharedLibraryCore.RCon
|
|||||||
throw new NetworkException("Expected response but got 0 bytes back");
|
throw new NetworkException("Expected response but got 0 bytes back");
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.OnComplete.Release(1);
|
|
||||||
connectionState.ConnectionAttempts = 0;
|
connectionState.ConnectionAttempts = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,9 +170,16 @@ namespace SharedLibraryCore.RCon
|
|||||||
goto retrySend;
|
goto retrySend;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.OnComplete.Release(1);
|
|
||||||
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"].FormatExt(Endpoint));
|
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"].FormatExt(Endpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (connectionState.OnComplete.CurrentCount == 0)
|
||||||
|
{
|
||||||
|
connectionState.OnComplete.Release(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string responseString = defaultEncoding.GetString(response, 0, response.Length) + '\n';
|
string responseString = defaultEncoding.GetString(response, 0, response.Length) + '\n';
|
||||||
@ -258,7 +271,7 @@ namespace SharedLibraryCore.RCon
|
|||||||
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
private void OnDataSent(object sender, SocketAsyncEventArgs e)
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
Log.WriteDebug($"Sent {e.Buffer.Length} bytes to {e.ConnectSocket.RemoteEndPoint.ToString()}");
|
Log.WriteDebug($"Sent {e.Buffer?.Length} bytes to {e.ConnectSocket?.RemoteEndPoint?.ToString()}");
|
||||||
#endif
|
#endif
|
||||||
ActiveQueries[this.Endpoint].OnSentData.Set();
|
ActiveQueries[this.Endpoint].OnSentData.Set();
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
<Compile Remove="Migrations\20181127143920_AddEndpointToEFServerUpdateServerIdType.cs" />
|
<Compile Remove="Migrations\20181127143920_AddEndpointToEFServerUpdateServerIdType.cs" />
|
||||||
<Compile Remove="Migrations\20190222234606_AddIndexToEFMeta-KeyAndClientId.cs" />
|
<Compile Remove="Migrations\20190222234606_AddIndexToEFMeta-KeyAndClientId.cs" />
|
||||||
<Compile Remove="Migrations\20190223012312_SetMaxLengthForMetaKey.cs" />
|
<Compile Remove="Migrations\20190223012312_SetMaxLengthForMetaKey.cs" />
|
||||||
|
<Compile Remove="Migrations\20190907222702_AddMomentViewAnglesToAcSnapshot.cs" />
|
||||||
|
<Compile Remove="Migrations\20190907222702_AddMomentViewAnglesToAcSnapshot.Designer.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -46,7 +48,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.2.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||||
<PackageReference Include="Npgsql" Version="4.0.7" />
|
<PackageReference Include="Npgsql" Version="4.0.9" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.4" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ namespace WebfrontCore.Controllers
|
|||||||
if (!_fileCache.ContainsKey(fileName))
|
if (!_fileCache.ContainsKey(fileName))
|
||||||
{
|
{
|
||||||
|
|
||||||
string path = $"wwwroot\\css\\{fileName}";
|
string path = $"wwwroot{Path.DirectorySeparatorChar}css{Path.DirectorySeparatorChar}{fileName}";
|
||||||
string data = await System.IO.File.ReadAllTextAsync(path);
|
string data = await System.IO.File.ReadAllTextAsync(path);
|
||||||
data = await Manager.MiddlewareActionHandler.Execute(data, "custom_css_accent");
|
data = await Manager.MiddlewareActionHandler.Execute(data, "custom_css_accent");
|
||||||
_fileCache.Add(fileName, data);
|
_fileCache.Add(fileName, data);
|
||||||
|
@ -6,8 +6,8 @@ init()
|
|||||||
{
|
{
|
||||||
SetDvarIfUninitialized( "sv_customcallbacks", true );
|
SetDvarIfUninitialized( "sv_customcallbacks", true );
|
||||||
SetDvarIfUninitialized( "sv_framewaittime", 0.05 );
|
SetDvarIfUninitialized( "sv_framewaittime", 0.05 );
|
||||||
SetDvarIfUninitialized( "sv_additionalwaittime", 0.05 );
|
SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 );
|
||||||
SetDvarIfUninitialized( "sv_maxstoredframes", 4 );
|
SetDvarIfUninitialized( "sv_maxstoredframes", 12 );
|
||||||
SetDvarIfUninitialized( "sv_printradarupdates", false );
|
SetDvarIfUninitialized( "sv_printradarupdates", false );
|
||||||
SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 );
|
SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 );
|
||||||
SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" );
|
SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" );
|
||||||
@ -111,6 +111,11 @@ waitForFrameThread()
|
|||||||
self.currentAnglePosition = 0;
|
self.currentAnglePosition = 0;
|
||||||
self.anglePositions = [];
|
self.anglePositions = [];
|
||||||
|
|
||||||
|
for (i = 0; i < getDvarInt( "sv_maxstoredframes" ); i++)
|
||||||
|
{
|
||||||
|
self.anglePositions[i] = self getPlayerAngles();
|
||||||
|
}
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
self.anglePositions[self.currentAnglePosition] = self getPlayerAngles();
|
self.anglePositions[self.currentAnglePosition] = self getPlayerAngles();
|
||||||
@ -119,34 +124,55 @@ waitForFrameThread()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
waitForAdditionalAngles( logString )
|
waitForAdditionalAngles( logString, beforeFrameCount, afterFrameCount )
|
||||||
{
|
{
|
||||||
wait( getDvarFloat( "sv_additionalwaittime" ) );
|
currentIndex = self.currentAnglePosition;
|
||||||
|
wait( 0.05 * afterFrameCount );
|
||||||
|
|
||||||
self.angleSnapshot = [];
|
self.angleSnapshot = [];
|
||||||
|
|
||||||
for( i = 0; i < getDvarInt( "sv_maxstoredframes" ); i++ )
|
for( j = 0; j < self.anglePositions.size; j++ )
|
||||||
{
|
{
|
||||||
self.angleSnapshot[i] = self.anglePositions[i];
|
self.angleSnapshot[j] = self.anglePositions[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPos = self.currentAnglePosition;
|
|
||||||
anglesStr = "";
|
anglesStr = "";
|
||||||
|
collectedFrames = 0;
|
||||||
|
i = currentIndex - beforeFrameCount;
|
||||||
|
|
||||||
i = 0;
|
while (collectedFrames < beforeFrameCount)
|
||||||
|
|
||||||
if ( currentPos < getDvarInt( "sv_maxstoredframes" ) - 1 )
|
|
||||||
{
|
{
|
||||||
i = currentPos + 1;
|
fixedIndex = i;
|
||||||
|
if (i < 0)
|
||||||
|
{
|
||||||
|
fixedIndex = self.angleSnapshot.size - abs(i);
|
||||||
|
}
|
||||||
|
anglesStr += self.angleSnapshot[fixedIndex] + ":";
|
||||||
|
collectedFrames++;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( i != currentPos )
|
if (i == currentIndex)
|
||||||
{
|
{
|
||||||
anglesStr += self.angleSnapshot[i] + ":";
|
anglesStr += self.angleSnapshot[i] + ":";
|
||||||
i = (i + 1) % getDvarInt( "sv_maxstoredframes" );
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
logPrint( logString + ";" + anglesStr + "\n" );
|
collectedFrames = 0;
|
||||||
|
|
||||||
|
while (collectedFrames < afterFrameCount)
|
||||||
|
{
|
||||||
|
fixedIndex = i;
|
||||||
|
if (i > self.angleSnapshot.size - 1)
|
||||||
|
{
|
||||||
|
fixedIndex = i % self.angleSnapshot.size;
|
||||||
|
}
|
||||||
|
anglesStr += self.angleSnapshot[fixedIndex] + ":";
|
||||||
|
collectedFrames++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
logPrint(logString + ";" + anglesStr + "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
vectorScale( vector, scale )
|
vectorScale( vector, scale )
|
||||||
@ -156,6 +182,11 @@ vectorScale( vector, scale )
|
|||||||
|
|
||||||
Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon )
|
Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon )
|
||||||
{
|
{
|
||||||
|
if (sMeansOfDeath == "MOD_FALLING" || !isPlayer(attacker))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
victim = self;
|
victim = self;
|
||||||
_attacker = attacker;
|
_attacker = attacker;
|
||||||
|
|
||||||
@ -172,8 +203,8 @@ Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon )
|
|||||||
location = victim GetTagOrigin( hitLocationToBone( sHitLoc ) );
|
location = victim GetTagOrigin( hitLocationToBone( sHitLoc ) );
|
||||||
isKillstreakKill = !isPlayer( attacker ) || isKillstreakWeapon( sWeapon );
|
isKillstreakKill = !isPlayer( attacker ) || isKillstreakWeapon( sWeapon );
|
||||||
|
|
||||||
logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0;";
|
logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + gettime() + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0";
|
||||||
attacker thread waitForAdditionalAngles( logLine );
|
attacker thread waitForAdditionalAngles( logLine, 2, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
Callback_PlayerDamage( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
Callback_PlayerDamage( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
|
||||||
|
@ -6,6 +6,7 @@ Version 2.4:
|
|||||||
-added ability to customize accent color and branding on webfront
|
-added ability to customize accent color and branding on webfront
|
||||||
-added flag button to client profile
|
-added flag button to client profile
|
||||||
-hid flagged status of users on webfront unless logged in
|
-hid flagged status of users on webfront unless logged in
|
||||||
|
-added snap anticheat metric
|
||||||
|
|
||||||
Version 2.3:
|
Version 2.3:
|
||||||
-added configuration option to ignore bots
|
-added configuration option to ignore bots
|
||||||
|
Loading…
x
Reference in New Issue
Block a user