more stat SPM fixes
prevent null say event from executing when exiting adjusted rcon and socket timeout fixed bug with login/setpassword not working after claiming ownership
This commit is contained in:
parent
3a463be7f8
commit
f442f251f6
@ -27,6 +27,10 @@
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
|
||||
<Private>true</Private>
|
||||
|
@ -54,6 +54,18 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
};
|
||||
}
|
||||
|
||||
if (cleanedEventLine[0] == 'D')
|
||||
{
|
||||
return new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Damage,
|
||||
Data = Regex.Replace(logLine, @"[0-9]+:[0-9]+\ ", "").Trim(),
|
||||
Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[5].ConvertLong()),
|
||||
Target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()),
|
||||
Owner = server
|
||||
};
|
||||
}
|
||||
|
||||
if (cleanedEventLine.Contains("ExitLevel"))
|
||||
{
|
||||
return new GameEvent()
|
||||
|
@ -27,7 +27,8 @@ namespace IW4MAdmin.Application
|
||||
#endif
|
||||
// we need this to keep accurate track of the score
|
||||
if (gameEvent.Type == GameEvent.EventType.Script ||
|
||||
gameEvent.Type == GameEvent.EventType.Kill)
|
||||
gameEvent.Type == GameEvent.EventType.Kill ||
|
||||
gameEvent.Type == GameEvent.EventType.MapChange)
|
||||
{
|
||||
#if DEBUG
|
||||
Manager.GetLogger().WriteDebug($"Added sensitive event to queue");
|
||||
|
@ -117,9 +117,12 @@ namespace IW4MAdmin.Application
|
||||
continue;
|
||||
}
|
||||
|
||||
if (userInput?.Length > 0)
|
||||
{
|
||||
Origin.CurrentServer = ServerManager.Servers[0];
|
||||
GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]);
|
||||
ServerManager.GetEventHandler().AddEvent(E);
|
||||
}
|
||||
Console.Write('>');
|
||||
|
||||
} while (ServerManager.Running);
|
||||
|
@ -23,11 +23,11 @@ namespace Application.Misc
|
||||
string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
|
||||
var responseJson = JsonConvert.DeserializeObject<JObject>(response);
|
||||
int blockType = Convert.ToInt32(responseJson["block"]);
|
||||
if (responseJson.ContainsKey("isp"))
|
||||
/*if (responseJson.ContainsKey("isp"))
|
||||
{
|
||||
if (responseJson["isp"].ToString() == "TSF-IP-CORE")
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
return blockType == 1;
|
||||
}
|
||||
}
|
||||
|
@ -80,13 +80,16 @@ namespace Application.RconParsers
|
||||
if (Status.Length < 4)
|
||||
throw new ServerException("Unexpected status response received");
|
||||
|
||||
int validMatches = 0;
|
||||
foreach (String S in Status)
|
||||
{
|
||||
String responseLine = S.Trim();
|
||||
|
||||
var regex = Regex.Match(responseLine, StatusRegex, RegexOptions.IgnoreCase);
|
||||
|
||||
if (regex.Success)
|
||||
{
|
||||
validMatches++;
|
||||
int clientNumber = int.Parse(regex.Groups[1].Value);
|
||||
int score = int.Parse(regex.Groups[2].Value);
|
||||
|
||||
@ -113,10 +116,26 @@ namespace Application.RconParsers
|
||||
IsBot = ip == 0
|
||||
};
|
||||
|
||||
if (P.IsBot)
|
||||
{
|
||||
P.NetworkId = -(P.ClientNumber + 1);
|
||||
P.IPAddress = P.ClientNumber + 1;
|
||||
}
|
||||
|
||||
StatusPlayers.Add(P);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Status.Length > 5 && validMatches == 0)
|
||||
{
|
||||
IW4MAdmin.Application.Program.ServerManager.Logger.WriteError("BAD STATUS!");
|
||||
foreach (var s in Status)
|
||||
{
|
||||
IW4MAdmin.Application.Program.ServerManager.Logger.WriteDebug(s);
|
||||
}
|
||||
}
|
||||
|
||||
return StatusPlayers;
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,15 @@ namespace IW4MAdmin
|
||||
|
||||
var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress);
|
||||
var currentBan = activePenalties.FirstOrDefault(b => b.Expires > DateTime.UtcNow);
|
||||
var currentAutoFlag = activePenalties.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1)
|
||||
.OrderByDescending(p => p.When)
|
||||
.FirstOrDefault();
|
||||
|
||||
// remove their auto flag status after a week
|
||||
if (currentAutoFlag != null && (DateTime.Now - currentAutoFlag.When).TotalDays > 7)
|
||||
{
|
||||
player.Level = Player.Permission.User;
|
||||
}
|
||||
|
||||
if (currentBan != null)
|
||||
{
|
||||
@ -189,7 +198,7 @@ namespace IW4MAdmin
|
||||
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
|
||||
e.OnProcessed.Wait();
|
||||
e.OnProcessed.WaitHandle.WaitOne(5000);
|
||||
|
||||
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
|
||||
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey))
|
||||
@ -218,7 +227,7 @@ namespace IW4MAdmin
|
||||
|
||||
var e = new GameEvent(GameEvent.EventType.Disconnect, "", Leaving, null, this);
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
e.OnProcessed.Wait();
|
||||
e.OnProcessed.WaitHandle.WaitOne(5000);
|
||||
|
||||
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
|
||||
Leaving.LastConnection = DateTime.UtcNow;
|
||||
@ -459,10 +468,10 @@ namespace IW4MAdmin
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Script)
|
||||
{
|
||||
Manager.GetEventHandler().AddEvent(GameEvent.TranferWaiter(GameEvent.EventType.Kill, E));
|
||||
Manager.GetEventHandler().AddEvent(GameEvent.TransferWaiter(GameEvent.EventType.Kill, E));
|
||||
}
|
||||
|
||||
if (E.Type == GameEvent.EventType.Say && E.Data.Length >= 2)
|
||||
if (E.Type == GameEvent.EventType.Say && E.Data?.Length >= 2)
|
||||
{
|
||||
if (E.Data.Substring(0, 1) == "!" ||
|
||||
E.Data.Substring(0, 1) == "@" ||
|
||||
@ -492,7 +501,7 @@ namespace IW4MAdmin
|
||||
|
||||
|
||||
// reprocess event as a command
|
||||
Manager.GetEventHandler().AddEvent(GameEvent.TranferWaiter(GameEvent.EventType.Command, E));
|
||||
Manager.GetEventHandler().AddEvent(GameEvent.TransferWaiter(GameEvent.EventType.Command, E));
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,12 +527,21 @@ namespace IW4MAdmin
|
||||
{
|
||||
var dict = await this.GetInfoAsync();
|
||||
|
||||
Gametype = dict["gametype"].StripColors();
|
||||
Hostname = dict["hostname"].StripColors();
|
||||
if (dict == null)
|
||||
{
|
||||
Logger.WriteWarning("Map change event response doesn't have any data");
|
||||
}
|
||||
|
||||
string mapname = dict["mapname"].StripColors();
|
||||
else
|
||||
{
|
||||
|
||||
Gametype = dict["gametype"].StripColors();
|
||||
Hostname = dict["hostname"]?.StripColors();
|
||||
|
||||
string mapname = dict["mapname"]?.StripColors() ?? CurrentMap.Name;
|
||||
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
@ -827,8 +845,6 @@ namespace IW4MAdmin
|
||||
|
||||
Logger.WriteInfo($"Log file is {logPath}");
|
||||
#if DEBUG
|
||||
// LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");
|
||||
#else
|
||||
await Broadcast(loc["BROADCAST_ONLINE"]);
|
||||
#endif
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Objects;
|
||||
using IW4MAdmin.Plugins.Stats.Helpers;
|
||||
using IW4MAdmin.Plugins.Stats.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
@ -19,6 +19,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
EFClientStatistics ClientStats;
|
||||
DateTime LastKill;
|
||||
ILogger Log;
|
||||
Strain Strain;
|
||||
|
||||
public Detection(ILogger log, EFClientStatistics clientStats)
|
||||
{
|
||||
@ -26,8 +27,28 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
HitLocationCount = new Dictionary<IW4Info.HitLocation, int>();
|
||||
foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation)))
|
||||
HitLocationCount.Add((IW4Info.HitLocation)loc, 0);
|
||||
LastKill = DateTime.UtcNow;
|
||||
ClientStats = clientStats;
|
||||
Strain = new Strain();
|
||||
}
|
||||
|
||||
public void ProcessDamage(string damageLine)
|
||||
{
|
||||
string regex = @"^(D);((?:bot[0-9]+)|(?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[A-Z]|[0-9])+);([0-9]+);(axis|allies);(.+);((?:[0-9]+|[a-z]+|_)+);([0-9]+);((?:[A-Z]|_)+);((?:[a-z]|_)+)$";
|
||||
|
||||
var match = Regex.Match(damageLine, regex, RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
var meansOfDeath = ParseEnum<IW4Info.MeansOfDeath>.Get(match.Groups[12].Value, typeof(IW4Info.MeansOfDeath));
|
||||
var hitLocation = ParseEnum<IW4Info.HitLocation>.Get(match.Groups[13].Value, typeof(IW4Info.HitLocation));
|
||||
|
||||
if (meansOfDeath == IW4Info.MeansOfDeath.MOD_PISTOL_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_RIFLE_BULLET ||
|
||||
meansOfDeath == IW4Info.MeansOfDeath.MOD_HEAD_SHOT)
|
||||
{
|
||||
ClientStats.HitLocations.First(hl => hl.Location == hitLocation).HitCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -47,20 +68,82 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
RatioAmount = 0
|
||||
};
|
||||
|
||||
if (LastKill == DateTime.MinValue)
|
||||
LastKill = DateTime.UtcNow;
|
||||
|
||||
HitLocationCount[kill.HitLoc]++;
|
||||
Kills++;
|
||||
AverageKillTime = (AverageKillTime + (DateTime.UtcNow - LastKill).TotalSeconds) / Kills;
|
||||
|
||||
#region SNAPSHOTS
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region VIEWANGLES
|
||||
double distance = Vector3.Distance(kill.KillOrigin, kill.DeathOrigin);
|
||||
/*double distance = Vector3.Distance(kill.KillOrigin, kill.DeathOrigin);
|
||||
double x = kill.KillOrigin.X + distance * Math.Cos(kill.ViewAngles.X.ToRadians()) * Math.Cos(kill.ViewAngles.Y.ToRadians());
|
||||
double y = kill.KillOrigin.Y + (distance * Math.Sin(kill.ViewAngles.X.ToRadians()) * Math.Cos(kill.ViewAngles.Y.ToRadians()));
|
||||
double z = kill.KillOrigin.Z + distance * Math.Sin((360.0f - kill.ViewAngles.Y).ToRadians());
|
||||
var trueVector = Vector3.Subtract(kill.KillOrigin, kill.DeathOrigin);
|
||||
var calculatedVector = Vector3.Subtract(kill.KillOrigin, new Vector3((float)x, (float)y, (float)z));
|
||||
double angle = trueVector.AngleBetween(calculatedVector);
|
||||
double angle = trueVector.AngleBetween(calculatedVector);*/
|
||||
|
||||
if (kill.AdsPercent > 0.5 && kill.Distance > 3)
|
||||
|
||||
// make sure it's divisible by 2
|
||||
if (kill.AnglesList.Count % 2 == 0)
|
||||
{
|
||||
double maxDistance = 0;
|
||||
for (int i = 0; i < kill.AnglesList.Count - 1; i += 1)
|
||||
{
|
||||
// Log.WriteDebug($"Fixed 1 {kill.AnglesList[i]}");
|
||||
// Log.WriteDebug($"Fixed 2 {kill.AnglesList[i + 1]}");
|
||||
|
||||
// fix max distance
|
||||
double currDistance = Vector3.AbsoluteDistance(kill.AnglesList[i], kill.AnglesList[i + 1]);
|
||||
//Log.WriteDebug($"Distance {currDistance}");
|
||||
if (currDistance > maxDistance)
|
||||
{
|
||||
maxDistance = currDistance;
|
||||
}
|
||||
}
|
||||
|
||||
double realAgainstPredict = Vector3.AbsoluteDistance(kill.ViewAngles, kill.AnglesList[10]);
|
||||
|
||||
var hitLoc = ClientStats.HitLocations
|
||||
.First(hl => hl.Location == kill.HitLoc);
|
||||
float previousAverage = hitLoc.HitOffsetAverage;
|
||||
double newAverage = (previousAverage * (hitLoc.HitCount - 1) + realAgainstPredict) / hitLoc.HitCount;
|
||||
hitLoc.HitOffsetAverage = (float)newAverage;
|
||||
|
||||
if (maxDistance > hitLoc.MaxAngleDistance)
|
||||
hitLoc.MaxAngleDistance = (float)maxDistance;
|
||||
|
||||
if (double.IsNaN(hitLoc.HitOffsetAverage))
|
||||
{
|
||||
Log.WriteWarning("[Detection::ProcessKill] HitOffsetAvgerage NaN");
|
||||
Log.WriteDebug($"{previousAverage}-{hitLoc.HitCount}-{hitLoc}-{newAverage}");
|
||||
hitLoc.HitOffsetAverage = 0f;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"MaxDistance={maxDistance}, PredictVsReal={realAgainstPredict}");
|
||||
#endif
|
||||
}
|
||||
|
||||
var currentStrain = Strain.GetStrain(kill.ViewAngles, (kill.When - LastKill).TotalMilliseconds);
|
||||
|
||||
if (currentStrain > ClientStats.MaxStrain)
|
||||
{
|
||||
ClientStats.MaxStrain = currentStrain;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Current Strain: {currentStrain}");
|
||||
#endif
|
||||
|
||||
/*if (kill.AdsPercent > 0.5 && kill.Distance > 3)
|
||||
{
|
||||
var hitLoc = ClientStats.HitLocations
|
||||
.First(hl => hl.Location == kill.HitLoc);
|
||||
@ -74,7 +157,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
Log.WriteDebug($"{previousAverage}-{hitLoc.HitCount}-{hitLoc}-{newAverage}");
|
||||
hitLoc.HitOffsetAverage = 0f;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
LastKill = kill.When;
|
||||
|
||||
#endregion
|
||||
|
||||
|
47
Plugins/Stats/Cheat/Strain.cs
Normal file
47
Plugins/Stats/Cheat/Strain.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using SharedLibraryCore.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Cheat
|
||||
{
|
||||
class Strain
|
||||
{
|
||||
private static double StrainDecayBase = 0.15;
|
||||
private double CurrentStrain;
|
||||
private Vector3 LastAngle;
|
||||
|
||||
public double GetStrain(Vector3 newAngle, double deltaTime)
|
||||
{
|
||||
if (LastAngle == null)
|
||||
LastAngle = newAngle;
|
||||
|
||||
double decayFactor = GetDecay(deltaTime);
|
||||
CurrentStrain *= decayFactor;
|
||||
|
||||
double[] distance = Helpers.Extensions.AngleStuff(newAngle, LastAngle);
|
||||
|
||||
// this happens on first kill
|
||||
if ((distance[0] == 0 && distance[1] == 0) ||
|
||||
deltaTime == 0 ||
|
||||
double.IsNaN(CurrentStrain))
|
||||
{
|
||||
return CurrentStrain;
|
||||
}
|
||||
|
||||
double newStrain = Math.Pow(distance[0] + distance[1], 0.99) / deltaTime;
|
||||
|
||||
if (newStrain + CurrentStrain > 0.25)
|
||||
{
|
||||
Console.WriteLine($"{LastAngle}-{newAngle}-{decayFactor}-{CurrentStrain}-{newStrain}-{distance[0]}-{distance[1]}-{deltaTime}");
|
||||
}
|
||||
|
||||
CurrentStrain += newStrain;
|
||||
LastAngle = newAngle;
|
||||
|
||||
return CurrentStrain;
|
||||
}
|
||||
|
||||
private double GetDecay(double deltaTime) => Math.Pow(StrainDecayBase, deltaTime / 1000.0);
|
||||
}
|
||||
}
|
@ -22,5 +22,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
public static float ToRadians(this float value) => (float)Math.PI * value / 180.0f;
|
||||
|
||||
public static float ToDegrees(this float value) => value * 180.0f / (float)Math.PI;
|
||||
|
||||
public static double[] AngleStuff(Vector3 a, Vector3 b)
|
||||
{
|
||||
double deltaX = 180.0 -Math.Abs(Math.Abs(a.X - b.X) - 180.0);
|
||||
double deltaY = 180.0 - Math.Abs(Math.Abs(a.Y - b.Y) - 180.0);
|
||||
|
||||
return new[] { deltaX, deltaY };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,8 +130,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// todo: look at this more
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
}
|
||||
|
||||
// migration for previous existing stats
|
||||
else if (clientStats.HitLocations.Count == 0)
|
||||
if (clientStats.HitLocations.Count == 0)
|
||||
{
|
||||
clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType<IW4Info.HitLocation>().Select(hl => new EFHitLocationCount()
|
||||
{
|
||||
@ -140,7 +146,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
Location = hl
|
||||
})
|
||||
.ToList();
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
//await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// set these on connecting
|
||||
@ -156,10 +162,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
|
||||
Log.WriteDebug("Could not add client to detection");
|
||||
|
||||
|
||||
// todo: look at this more
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
/*
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();*/
|
||||
|
||||
return clientStats;
|
||||
}
|
||||
@ -205,15 +209,24 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
// increment the total play time
|
||||
serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds;
|
||||
await statsSvc.ServerStatsSvc.SaveChangesAsync();
|
||||
//await statsSvc.ServerStatsSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public void AddDamageEvent(string eventLine, int clientId, int serverId)
|
||||
{
|
||||
if (Plugin.Config.Configuration().EnableAntiCheat)
|
||||
{
|
||||
var clientDetection = Servers[serverId].PlayerDetections[clientId];
|
||||
clientDetection.ProcessDamage(eventLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process stats for kill event
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task AddScriptKill(Player attacker, Player victim, int serverId, string map, string hitLoc, string type,
|
||||
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads)
|
||||
public async Task AddScriptKill(DateTime time, Player attacker, Player victim, int serverId, string map, string hitLoc, string type,
|
||||
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, string snapAngles)
|
||||
{
|
||||
var statsSvc = ContextThreads[serverId];
|
||||
Vector3 vDeathOrigin = null;
|
||||
@ -235,6 +248,22 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
return;
|
||||
}
|
||||
|
||||
var snapshotAngles = new List<Vector3>();
|
||||
|
||||
try
|
||||
{
|
||||
foreach(string angle in snapAngles.Split(':', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
snapshotAngles.Add(Vector3.Parse(angle).FixIW4Angles());
|
||||
}
|
||||
}
|
||||
|
||||
catch (FormatException)
|
||||
{
|
||||
Log.WriteWarning("Could not parse snapshot angles");
|
||||
return;
|
||||
}
|
||||
|
||||
var kill = new EFClientKill()
|
||||
{
|
||||
Active = true,
|
||||
@ -250,9 +279,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)),
|
||||
ViewAngles = vViewAngles,
|
||||
TimeOffset = Int64.Parse(offset),
|
||||
When = DateTime.UtcNow,
|
||||
When = time,
|
||||
IsKillstreakKill = isKillstreakKill[0] != '0',
|
||||
AdsPercent = float.Parse(Ads)
|
||||
AdsPercent = float.Parse(Ads),
|
||||
AnglesList = snapshotAngles
|
||||
};
|
||||
|
||||
if (kill.DeathType == IW4Info.MeansOfDeath.MOD_SUICIDE &&
|
||||
@ -280,7 +310,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1;
|
||||
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
// await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
//statsSvc.KillStatsSvc.Insert(kill);
|
||||
@ -290,6 +320,12 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
{
|
||||
async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
|
||||
{
|
||||
// prevent multiple bans from occuring
|
||||
if (attacker.Level == Player.Permission.Banned)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (penalty.ClientPenalty)
|
||||
{
|
||||
case Penalty.PenaltyType.Ban:
|
||||
@ -312,6 +348,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
await executePenalty(clientDetection.ProcessKill(kill));
|
||||
await executePenalty(clientDetection.ProcessTotalRatio(clientStats));
|
||||
|
||||
#if DEBUG
|
||||
statsSvc.ClientStatSvc.Update(clientStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,7 +367,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
Log.WriteError($"[Stats::AddStandardKill] kill attacker ClientId is invalid {attacker.ClientId}-{attacker}");
|
||||
// happens when the client has disconnected before the last status update
|
||||
Log.WriteWarning($"[Stats::AddStandardKill] kill attacker ClientId is invalid {attacker.ClientId}-{attacker}");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -338,7 +380,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
Log.WriteError($"[Stats::AddStandardKill] kill victim ClientId is invalid {victim.ClientId}-{victim}");
|
||||
Log.WriteWarning($"[Stats::AddStandardKill] kill victim ClientId is invalid {victim.ClientId}-{victim}");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -393,7 +435,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
var statsSvc = ContextThreads[serverId];
|
||||
statsSvc.ClientStatSvc.Update(attackerStats);
|
||||
statsSvc.ClientStatSvc.Update(victimStats);
|
||||
await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
//await statsSvc.ClientStatSvc.SaveChangesAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -451,6 +493,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
// calculate the players Score Per Minute for the current session
|
||||
int scoreDifference = clientStats.RoundScore - clientStats.LastScore;
|
||||
|
||||
// todo: fix the SPM for TEAMDAMAGE
|
||||
if (scoreDifference < 0)
|
||||
scoreDifference = clientStats.RoundScore;
|
||||
|
||||
double killSPM = scoreDifference / timeSinceLastCalc;
|
||||
|
||||
// calculate how much the KDR should weigh
|
||||
|
@ -4,6 +4,7 @@ using SharedLibraryCore.Database.Models;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Stats.Models
|
||||
{
|
||||
@ -38,5 +39,7 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
||||
public bool IsKillstreakKill { get; set; }
|
||||
[NotMapped]
|
||||
public float AdsPercent { get; set; }
|
||||
[NotMapped]
|
||||
public List<Vector3> AnglesList { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
||||
public double Skill { get; set; }
|
||||
[Required]
|
||||
public int TimePlayed { get; set; }
|
||||
[Required]
|
||||
public double MaxStrain { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public float AverageHitOffset
|
||||
|
@ -14,6 +14,9 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
||||
public int HitCount { get; set; }
|
||||
[Required]
|
||||
public float HitOffsetAverage { get; set; }
|
||||
[Required]
|
||||
public float MaxAngleDistance { get; set; }
|
||||
[Required]
|
||||
public int ClientId { get; set; }
|
||||
[ForeignKey("ClientId"), Column(Order = 0 )]
|
||||
public EFClient Client { get; set; }
|
||||
|
@ -74,13 +74,16 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
case GameEvent.EventType.Kill:
|
||||
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
|
||||
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback)
|
||||
await Manager.AddScriptKill(E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
|
||||
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12]);
|
||||
await Manager.AddScriptKill(E.Time, E.Origin, E.Target, S.GetHashCode(), 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]);
|
||||
else if (!E.Owner.CustomCallback)
|
||||
await Manager.AddStandardKill(E.Origin, E.Target);
|
||||
break;
|
||||
case GameEvent.EventType.Death:
|
||||
break;
|
||||
case GameEvent.EventType.Damage:
|
||||
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Owner.GetHashCode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +149,8 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
double abdomenRatio = 0;
|
||||
double chestAbdomenRatio = 0;
|
||||
double hitOffsetAverage = 0;
|
||||
double maxStrain = clientStats.Count(c=> c.MaxStrain > 0) == 0 ? 0 : clientStats.Max(cs => cs.MaxStrain);
|
||||
//double maxAngle = clientStats.Max(cs => cs.HitLocations.Max(hl => hl.MaxAngleDistance));
|
||||
|
||||
if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
|
||||
{
|
||||
@ -197,9 +202,21 @@ namespace IW4MAdmin.Plugins.Stats
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "Hit Offset Average",
|
||||
Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°",
|
||||
Value = $"{Math.Round(((float)hitOffsetAverage), 4)}°",
|
||||
Sensitive = true
|
||||
}
|
||||
},
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "Max Strain",
|
||||
Value = Math.Round(maxStrain, 3),
|
||||
Sensitive = true
|
||||
},
|
||||
/*new ProfileMeta()
|
||||
{
|
||||
Key = "Max Angle Distance",
|
||||
Value = Math.Round(maxAngle, 1),
|
||||
Sensitive = true
|
||||
}*/
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Objects;
|
||||
using SharedLibraryCore.Services;
|
||||
using System;
|
||||
@ -36,6 +35,8 @@ namespace SharedLibraryCore.Commands
|
||||
{
|
||||
E.Origin.Level = Player.Permission.Owner;
|
||||
await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_SUCCESS"]);
|
||||
// so setpassword/login works
|
||||
E.Owner.Manager.GetPrivilegedClients().Add(E.Origin.ClientId, E.Origin);
|
||||
await E.Owner.Manager.GetClientService().Update(E.Origin);
|
||||
}
|
||||
else
|
||||
|
@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using SharedLibraryCore.Objects;
|
||||
|
||||
@ -50,14 +47,16 @@ namespace SharedLibraryCore
|
||||
Target = T;
|
||||
Owner = S;
|
||||
OnProcessed = new ManualResetEventSlim();
|
||||
Time = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public GameEvent()
|
||||
{
|
||||
OnProcessed = new ManualResetEventSlim();
|
||||
Time = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public static GameEvent TranferWaiter(EventType newType, GameEvent e)
|
||||
public static GameEvent TransferWaiter(EventType newType, GameEvent e)
|
||||
{
|
||||
var newEvent = new GameEvent()
|
||||
{
|
||||
@ -69,11 +68,12 @@ namespace SharedLibraryCore
|
||||
Owner = e.Owner,
|
||||
Remote = e.Remote,
|
||||
Target = e.Target,
|
||||
Type = newType
|
||||
Type = newType,
|
||||
};
|
||||
|
||||
// hack: prevent the previous event from completing until this one is done
|
||||
e.OnProcessed = new ManualResetEventSlim();
|
||||
newEvent.Time = e.Time;
|
||||
|
||||
return newEvent;
|
||||
}
|
||||
@ -87,5 +87,6 @@ namespace SharedLibraryCore
|
||||
public Boolean Remote = false;
|
||||
public object Extra { get; set; }
|
||||
public ManualResetEventSlim OnProcessed { get; set; }
|
||||
public DateTime Time { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@ -44,6 +44,19 @@ namespace SharedLibraryCore.Helpers
|
||||
return Math.Sqrt(Math.Pow(b.X - a.X, 2) + Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.Z - a.Z, 2));
|
||||
}
|
||||
|
||||
public static double AbsoluteDistance(Vector3 a, Vector3 b)
|
||||
{
|
||||
double deltaX = Math.Abs(b.X -a.X);
|
||||
double deltaY = Math.Abs(b.Y - a.Y);
|
||||
double deltaZ = Math.Abs(b.Z - a.Z);
|
||||
|
||||
double dx = deltaX < 360.0 / 2 ? deltaX : 360.0 - deltaX;
|
||||
double dy = deltaY < 360.0 / 2 ? deltaY : 360.0 - deltaY;
|
||||
double dz = deltaZ < 360.0 / 2 ? deltaZ : 360.0 - deltaZ;
|
||||
|
||||
return Math.Sqrt((dx * dx) + (dy * dy) + (dz * dx));
|
||||
}
|
||||
|
||||
public static Vector3 Subtract(Vector3 a, Vector3 b) => new Vector3(b.X - a.X, b.Y - a.Y, b.Z - a.Z);
|
||||
|
||||
public double DotProduct(Vector3 a) => (a.X * this.X) + (a.Y * this.Y) + (a.Z * this.Z);
|
||||
|
434
SharedLibraryCore/Migrations/20180502195450_Update.Designer.cs
generated
Normal file
434
SharedLibraryCore/Migrations/20180502195450_Update.Designer.cs
generated
Normal file
@ -0,0 +1,434 @@
|
||||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
[Migration("20180502195450_Update")]
|
||||
partial class Update
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
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<int>("HitLoc");
|
||||
|
||||
b.Property<int?>("KillOriginVector3Id");
|
||||
|
||||
b.Property<int>("Map");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<int>("VictimId");
|
||||
|
||||
b.Property<int?>("ViewAnglesVector3Id");
|
||||
|
||||
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<int>("ServerId");
|
||||
|
||||
b.Property<DateTime>("TimeSent");
|
||||
|
||||
b.HasKey("MessageId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFClientMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("Deaths");
|
||||
|
||||
b.Property<int>("Kills");
|
||||
|
||||
b.Property<double>("MaxStrain");
|
||||
|
||||
b.Property<double>("SPM");
|
||||
|
||||
b.Property<double>("Skill");
|
||||
|
||||
b.Property<int>("TimePlayed");
|
||||
|
||||
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<int>("ServerId")
|
||||
.HasColumnName("EFClientStatistics_ServerId");
|
||||
|
||||
b.HasKey("HitLocationCountId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("ClientId", "ServerId");
|
||||
|
||||
b.ToTable("EFHitLocationCounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||
{
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
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<int>("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();
|
||||
|
||||
b.HasKey("AliasId");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
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.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.EFPenalty", b =>
|
||||
{
|
||||
b.Property<int>("PenaltyId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<DateTime>("Expires");
|
||||
|
||||
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.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.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.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.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
|
||||
}
|
||||
}
|
||||
}
|
35
SharedLibraryCore/Migrations/20180502195450_Update.cs
Normal file
35
SharedLibraryCore/Migrations/20180502195450_Update.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
public partial class Update : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<float>(
|
||||
name: "MaxAngleDistance",
|
||||
table: "EFHitLocationCounts",
|
||||
nullable: false,
|
||||
defaultValue: 0f);
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "MaxStrain",
|
||||
table: "EFClientStatistics",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MaxAngleDistance",
|
||||
table: "EFHitLocationCounts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "MaxStrain",
|
||||
table: "EFClientStatistics");
|
||||
}
|
||||
}
|
||||
}
|
433
SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs
Normal file
433
SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs
Normal file
@ -0,0 +1,433 @@
|
||||
// <auto-generated />
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||
using SharedLibraryCore.Database;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
|
||||
namespace SharedLibraryCore.Migrations
|
||||
{
|
||||
[DbContext(typeof(DatabaseContext))]
|
||||
partial class DatabaseContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||
|
||||
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<int>("HitLoc");
|
||||
|
||||
b.Property<int?>("KillOriginVector3Id");
|
||||
|
||||
b.Property<int>("Map");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<int>("VictimId");
|
||||
|
||||
b.Property<int?>("ViewAnglesVector3Id");
|
||||
|
||||
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<int>("ServerId");
|
||||
|
||||
b.Property<DateTime>("TimeSent");
|
||||
|
||||
b.HasKey("MessageId");
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("EFClientMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||
{
|
||||
b.Property<int>("ClientId");
|
||||
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int>("Deaths");
|
||||
|
||||
b.Property<int>("Kills");
|
||||
|
||||
b.Property<double>("MaxStrain");
|
||||
|
||||
b.Property<double>("SPM");
|
||||
|
||||
b.Property<double>("Skill");
|
||||
|
||||
b.Property<int>("TimePlayed");
|
||||
|
||||
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<int>("ServerId")
|
||||
.HasColumnName("EFClientStatistics_ServerId");
|
||||
|
||||
b.HasKey("HitLocationCountId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.HasIndex("ClientId", "ServerId");
|
||||
|
||||
b.ToTable("EFHitLocationCounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||
{
|
||||
b.Property<int>("ServerId");
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
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<int>("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();
|
||||
|
||||
b.HasKey("AliasId");
|
||||
|
||||
b.HasIndex("LinkId");
|
||||
|
||||
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.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.EFPenalty", b =>
|
||||
{
|
||||
b.Property<int>("PenaltyId")
|
||||
.ValueGeneratedOnAdd();
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<DateTime>("Expires");
|
||||
|
||||
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.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.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.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.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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using SharedLibraryCore.Exceptions;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
@ -32,11 +33,31 @@ namespace SharedLibraryCore.RCon
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseEvent
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string[] Response { get; set; }
|
||||
public Task Awaiter
|
||||
{
|
||||
get
|
||||
{
|
||||
return Task.Run(() => FinishedEvent.Wait());
|
||||
}
|
||||
}
|
||||
private ManualResetEventSlim FinishedEvent;
|
||||
|
||||
public ResponseEvent()
|
||||
{
|
||||
FinishedEvent = new ManualResetEventSlim();
|
||||
}
|
||||
}
|
||||
|
||||
public class Connection
|
||||
{
|
||||
public IPEndPoint Endpoint { get; private set; }
|
||||
public string RConPassword { get; private set; }
|
||||
Socket ServerConnection;
|
||||
public ConcurrentQueue<ManualResetEventSlim> ResponseQueue;
|
||||
//Socket ServerConnection;
|
||||
ILogger Log;
|
||||
int FailedSends;
|
||||
int FailedReceives;
|
||||
@ -56,27 +77,13 @@ namespace SharedLibraryCore.RCon
|
||||
OnConnected = new ManualResetEvent(false);
|
||||
OnSent = new ManualResetEvent(false);
|
||||
OnReceived = new ManualResetEvent(false);
|
||||
|
||||
try
|
||||
{
|
||||
ServerConnection = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
ServerConnection.BeginConnect(Endpoint, new AsyncCallback(OnConnectedCallback), ServerConnection);
|
||||
if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout))
|
||||
throw new SocketException((int)SocketError.TimedOut);
|
||||
FailedSends = 0;
|
||||
}
|
||||
|
||||
catch (SocketException e)
|
||||
{
|
||||
throw new NetworkException(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
~Connection()
|
||||
{
|
||||
ServerConnection.Shutdown(SocketShutdown.Both);
|
||||
/*ServerConnection.Shutdown(SocketShutdown.Both);
|
||||
ServerConnection.Close();
|
||||
ServerConnection.Dispose();
|
||||
ServerConnection.Dispose();*/
|
||||
}
|
||||
|
||||
private void OnConnectedCallback(IAsyncResult ar)
|
||||
@ -106,8 +113,9 @@ namespace SharedLibraryCore.RCon
|
||||
{
|
||||
int sentByteNum = serverConnection.EndSend(ar);
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Sent {sentByteNum} bytes to {ServerConnection.RemoteEndPoint}");
|
||||
Log.WriteDebug($"Sent {sentByteNum} bytes to {serverConnection.RemoteEndPoint}");
|
||||
#endif
|
||||
// this is where we override our await to make it
|
||||
OnSent.Set();
|
||||
}
|
||||
|
||||
@ -128,7 +136,7 @@ namespace SharedLibraryCore.RCon
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"Received {bytesRead} bytes from {ServerConnection.RemoteEndPoint}");
|
||||
Log.WriteDebug($"Received {bytesRead} bytes from {serverConnection.RemoteEndPoint}");
|
||||
#endif
|
||||
FailedReceives = 0;
|
||||
connectionState.ResponseString.Append(Utilities.EncodingType.GetString(connectionState.Buffer, 0, bytesRead).TrimEnd('\0') + '\n');
|
||||
@ -138,7 +146,7 @@ namespace SharedLibraryCore.RCon
|
||||
|
||||
if (serverConnection.Available > 0)
|
||||
{
|
||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
serverConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||
}
|
||||
else
|
||||
@ -158,14 +166,19 @@ namespace SharedLibraryCore.RCon
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
Log.WriteWarning($"Tried to check for more available bytes for disposed socket on {Endpoint}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true)
|
||||
{
|
||||
// will this really prevent flooding?
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 150)
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 250)
|
||||
{
|
||||
await Task.Delay(150);
|
||||
await Task.Delay(250);
|
||||
}
|
||||
|
||||
LastQuery = DateTime.Now;
|
||||
@ -191,29 +204,37 @@ namespace SharedLibraryCore.RCon
|
||||
break;
|
||||
}
|
||||
|
||||
using (var socketConnection = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
|
||||
{
|
||||
socketConnection.BeginConnect(Endpoint, new AsyncCallback(OnConnectedCallback), socketConnection);
|
||||
|
||||
retrySend:
|
||||
try
|
||||
{
|
||||
ServerConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), ServerConnection);
|
||||
|
||||
if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout))
|
||||
throw new SocketException((int)SocketError.TimedOut);
|
||||
|
||||
socketConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), socketConnection);
|
||||
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
||||
|
||||
if (!success)
|
||||
{
|
||||
FailedSends++;
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"{FailedSends} failed sends to {ServerConnection.RemoteEndPoint.ToString()}");
|
||||
Log.WriteDebug($"{FailedSends} failed sends to {socketConnection.RemoteEndPoint.ToString()}");
|
||||
#endif
|
||||
if (FailedSends < 4)
|
||||
goto retrySend;
|
||||
else if (FailedSends == 4)
|
||||
Log.WriteError($"Failed to send data to {ServerConnection.RemoteEndPoint}");
|
||||
Log.WriteError($"Failed to send data to {socketConnection.RemoteEndPoint}");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (FailedSends >= 4)
|
||||
{
|
||||
Log.WriteVerbose($"Resumed send RCon connection with {ServerConnection.RemoteEndPoint}");
|
||||
Log.WriteVerbose($"Resumed send RCon connection with {socketConnection.RemoteEndPoint}");
|
||||
FailedSends = 0;
|
||||
}
|
||||
}
|
||||
@ -230,12 +251,12 @@ namespace SharedLibraryCore.RCon
|
||||
if (!waitForResponse)
|
||||
return await Task.FromResult(new string[] { "" });
|
||||
|
||||
var connectionState = new ConnectionState(ServerConnection);
|
||||
var connectionState = new ConnectionState(socketConnection);
|
||||
|
||||
retryReceive:
|
||||
try
|
||||
{
|
||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
socketConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
||||
|
||||
@ -244,18 +265,18 @@ namespace SharedLibraryCore.RCon
|
||||
|
||||
FailedReceives++;
|
||||
#if DEBUG
|
||||
Log.WriteDebug($"{FailedReceives} failed receives from {ServerConnection.RemoteEndPoint.ToString()}");
|
||||
Log.WriteDebug($"{FailedReceives} failed receives from {socketConnection.RemoteEndPoint.ToString()}");
|
||||
#endif
|
||||
if (FailedReceives < 4)
|
||||
goto retrySend;
|
||||
else if (FailedReceives == 4)
|
||||
{
|
||||
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||
Log.WriteError($"Failed to receive data from {socketConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||
}
|
||||
|
||||
if (FailedReceives >= 4)
|
||||
{
|
||||
throw new NetworkException($"Could not receive data from {ServerConnection.RemoteEndPoint}");
|
||||
throw new NetworkException($"Could not receive data from {socketConnection.RemoteEndPoint}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,7 +284,7 @@ namespace SharedLibraryCore.RCon
|
||||
{
|
||||
if (FailedReceives >= 4)
|
||||
{
|
||||
Log.WriteVerbose($"Resumed receive RCon connection from {ServerConnection.RemoteEndPoint}");
|
||||
Log.WriteVerbose($"Resumed receive RCon connection from {socketConnection.RemoteEndPoint}");
|
||||
FailedReceives = 0;
|
||||
}
|
||||
}
|
||||
@ -282,7 +303,7 @@ namespace SharedLibraryCore.RCon
|
||||
|
||||
else if (FailedReceives == 4)
|
||||
{
|
||||
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||
Log.WriteError($"Failed to receive data from {socketConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||
}
|
||||
|
||||
if (FailedReceives >= 4)
|
||||
@ -306,4 +327,5 @@ namespace SharedLibraryCore.RCon
|
||||
return splitResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,6 @@ namespace SharedLibraryCore.RCon
|
||||
}
|
||||
|
||||
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 2);
|
||||
public static readonly TimeSpan SocketTimeout = new TimeSpan(0, 0, 10);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,10 @@
|
||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Migrations\20180502195240_Update.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.2" />
|
||||
|
@ -28,7 +28,6 @@ namespace WebfrontCore.Controllers
|
||||
|
||||
public async Task<IActionResult> ExecuteAsync(int serverId, string command)
|
||||
{
|
||||
|
||||
var server = Manager.GetServers().First(s => s.GetHashCode() == serverId);
|
||||
var client = new Player()
|
||||
{
|
||||
@ -50,7 +49,7 @@ namespace WebfrontCore.Controllers
|
||||
Manager.GetEventHandler().AddEvent(remoteEvent);
|
||||
// wait for the event to process
|
||||
|
||||
await Task.Run(() => remoteEvent.OnProcessed.Wait());
|
||||
await Task.Run(() => remoteEvent.OnProcessed.WaitHandle.WaitOne(5000));
|
||||
var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
|
||||
|
||||
// remove the added command response
|
||||
|
@ -22,6 +22,10 @@
|
||||
<Configurations>Debug;Release;Prerelease</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="bower.json" />
|
||||
<Content Remove="bundleconfig.json" />
|
||||
|
Loading…
Reference in New Issue
Block a user