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:
RaidMax 2018-05-03 00:25:49 -05:00
parent 3a463be7f8
commit f442f251f6
26 changed files with 1382 additions and 169 deletions

View File

@ -27,6 +27,10 @@
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj"> <ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
<Private>true</Private> <Private>true</Private>

View File

@ -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")) if (cleanedEventLine.Contains("ExitLevel"))
{ {
return new GameEvent() return new GameEvent()

View File

@ -27,7 +27,8 @@ namespace IW4MAdmin.Application
#endif #endif
// we need this to keep accurate track of the score // we need this to keep accurate track of the score
if (gameEvent.Type == GameEvent.EventType.Script || if (gameEvent.Type == GameEvent.EventType.Script ||
gameEvent.Type == GameEvent.EventType.Kill) gameEvent.Type == GameEvent.EventType.Kill ||
gameEvent.Type == GameEvent.EventType.MapChange)
{ {
#if DEBUG #if DEBUG
Manager.GetLogger().WriteDebug($"Added sensitive event to queue"); Manager.GetLogger().WriteDebug($"Added sensitive event to queue");

View File

@ -117,9 +117,12 @@ namespace IW4MAdmin.Application
continue; continue;
} }
if (userInput?.Length > 0)
{
Origin.CurrentServer = ServerManager.Servers[0]; Origin.CurrentServer = ServerManager.Servers[0];
GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]); GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]);
ServerManager.GetEventHandler().AddEvent(E); ServerManager.GetEventHandler().AddEvent(E);
}
Console.Write('>'); Console.Write('>');
} while (ServerManager.Running); } while (ServerManager.Running);

View File

@ -23,11 +23,11 @@ namespace Application.Misc
string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}"); string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
var responseJson = JsonConvert.DeserializeObject<JObject>(response); var responseJson = JsonConvert.DeserializeObject<JObject>(response);
int blockType = Convert.ToInt32(responseJson["block"]); int blockType = Convert.ToInt32(responseJson["block"]);
if (responseJson.ContainsKey("isp")) /*if (responseJson.ContainsKey("isp"))
{ {
if (responseJson["isp"].ToString() == "TSF-IP-CORE") if (responseJson["isp"].ToString() == "TSF-IP-CORE")
return true; return true;
} }*/
return blockType == 1; return blockType == 1;
} }
} }

View File

@ -80,13 +80,16 @@ namespace Application.RconParsers
if (Status.Length < 4) if (Status.Length < 4)
throw new ServerException("Unexpected status response received"); throw new ServerException("Unexpected status response received");
int validMatches = 0;
foreach (String S in Status) foreach (String S in Status)
{ {
String responseLine = S.Trim(); String responseLine = S.Trim();
var regex = Regex.Match(responseLine, StatusRegex, RegexOptions.IgnoreCase); var regex = Regex.Match(responseLine, StatusRegex, RegexOptions.IgnoreCase);
if (regex.Success) if (regex.Success)
{ {
validMatches++;
int clientNumber = int.Parse(regex.Groups[1].Value); int clientNumber = int.Parse(regex.Groups[1].Value);
int score = int.Parse(regex.Groups[2].Value); int score = int.Parse(regex.Groups[2].Value);
@ -113,10 +116,26 @@ namespace Application.RconParsers
IsBot = ip == 0 IsBot = ip == 0
}; };
if (P.IsBot)
{
P.NetworkId = -(P.ClientNumber + 1);
P.IPAddress = P.ClientNumber + 1;
}
StatusPlayers.Add(P); 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; return StatusPlayers;
} }
} }

View File

@ -161,6 +161,15 @@ namespace IW4MAdmin
var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress); var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress);
var currentBan = activePenalties.FirstOrDefault(b => b.Expires > DateTime.UtcNow); 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) if (currentBan != null)
{ {
@ -189,7 +198,7 @@ namespace IW4MAdmin
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this); var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
Manager.GetEventHandler().AddEvent(e); Manager.GetEventHandler().AddEvent(e);
e.OnProcessed.Wait(); e.OnProcessed.WaitHandle.WaitOne(5000);
if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs && if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs &&
await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey)) 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); var e = new GameEvent(GameEvent.EventType.Disconnect, "", Leaving, null, this);
Manager.GetEventHandler().AddEvent(e); Manager.GetEventHandler().AddEvent(e);
e.OnProcessed.Wait(); e.OnProcessed.WaitHandle.WaitOne(5000);
Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds; Leaving.TotalConnectionTime += (int)(DateTime.UtcNow - Leaving.ConnectionTime).TotalSeconds;
Leaving.LastConnection = DateTime.UtcNow; Leaving.LastConnection = DateTime.UtcNow;
@ -459,10 +468,10 @@ namespace IW4MAdmin
else if (E.Type == GameEvent.EventType.Script) 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) == "!" || if (E.Data.Substring(0, 1) == "!" ||
E.Data.Substring(0, 1) == "@" || E.Data.Substring(0, 1) == "@" ||
@ -492,7 +501,7 @@ namespace IW4MAdmin
// reprocess event as a command // 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(); var dict = await this.GetInfoAsync();
Gametype = dict["gametype"].StripColors(); if (dict == null)
Hostname = dict["hostname"].StripColors(); {
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 }; CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
} }
}
else else
{ {
@ -827,8 +845,6 @@ namespace IW4MAdmin
Logger.WriteInfo($"Log file is {logPath}"); Logger.WriteInfo($"Log file is {logPath}");
#if DEBUG #if DEBUG
// LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php");
#else
await Broadcast(loc["BROADCAST_ONLINE"]); await Broadcast(loc["BROADCAST_ONLINE"]);
#endif #endif
} }

View File

@ -1,12 +1,12 @@
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Objects; using SharedLibraryCore.Objects;
using IW4MAdmin.Plugins.Stats.Helpers;
using IW4MAdmin.Plugins.Stats.Models; using IW4MAdmin.Plugins.Stats.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
namespace IW4MAdmin.Plugins.Stats.Cheat namespace IW4MAdmin.Plugins.Stats.Cheat
{ {
@ -19,6 +19,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
EFClientStatistics ClientStats; EFClientStatistics ClientStats;
DateTime LastKill; DateTime LastKill;
ILogger Log; ILogger Log;
Strain Strain;
public Detection(ILogger log, EFClientStatistics clientStats) public Detection(ILogger log, EFClientStatistics clientStats)
{ {
@ -26,8 +27,28 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
HitLocationCount = new Dictionary<IW4Info.HitLocation, int>(); HitLocationCount = new Dictionary<IW4Info.HitLocation, int>();
foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation))) foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation)))
HitLocationCount.Add((IW4Info.HitLocation)loc, 0); HitLocationCount.Add((IW4Info.HitLocation)loc, 0);
LastKill = DateTime.UtcNow;
ClientStats = clientStats; 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> /// <summary>
@ -47,20 +68,82 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
RatioAmount = 0 RatioAmount = 0
}; };
if (LastKill == DateTime.MinValue)
LastKill = DateTime.UtcNow;
HitLocationCount[kill.HitLoc]++; HitLocationCount[kill.HitLoc]++;
Kills++; Kills++;
AverageKillTime = (AverageKillTime + (DateTime.UtcNow - LastKill).TotalSeconds) / Kills; AverageKillTime = (AverageKillTime + (DateTime.UtcNow - LastKill).TotalSeconds) / Kills;
#region SNAPSHOTS
#endregion
#region VIEWANGLES #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 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 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()); double z = kill.KillOrigin.Z + distance * Math.Sin((360.0f - kill.ViewAngles.Y).ToRadians());
var trueVector = Vector3.Subtract(kill.KillOrigin, kill.DeathOrigin); var trueVector = Vector3.Subtract(kill.KillOrigin, kill.DeathOrigin);
var calculatedVector = Vector3.Subtract(kill.KillOrigin, new Vector3((float)x, (float)y, (float)z)); 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 var hitLoc = ClientStats.HitLocations
.First(hl => hl.Location == kill.HitLoc); .First(hl => hl.Location == kill.HitLoc);
@ -74,7 +157,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
Log.WriteDebug($"{previousAverage}-{hitLoc.HitCount}-{hitLoc}-{newAverage}"); Log.WriteDebug($"{previousAverage}-{hitLoc.HitCount}-{hitLoc}-{newAverage}");
hitLoc.HitOffsetAverage = 0f; hitLoc.HitOffsetAverage = 0f;
} }
} }*/
LastKill = kill.When;
#endregion #endregion

View 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);
}
}

View File

@ -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 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 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 };
}
} }
} }

View File

@ -130,8 +130,14 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
await statsSvc.ClientStatSvc.SaveChangesAsync(); await statsSvc.ClientStatSvc.SaveChangesAsync();
} }
else
{
// todo: look at this more
statsSvc.ClientStatSvc.Update(clientStats);
}
// migration for previous existing stats // 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() 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 Location = hl
}) })
.ToList(); .ToList();
await statsSvc.ClientStatSvc.SaveChangesAsync(); //await statsSvc.ClientStatSvc.SaveChangesAsync();
} }
// set these on connecting // set these on connecting
@ -156,10 +162,8 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats))) if (!detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)))
Log.WriteDebug("Could not add client to detection"); Log.WriteDebug("Could not add client to detection");
/*
// todo: look at this more await statsSvc.ClientStatSvc.SaveChangesAsync();*/
statsSvc.ClientStatSvc.Update(clientStats);
await statsSvc.ClientStatSvc.SaveChangesAsync();
return clientStats; return clientStats;
} }
@ -205,15 +209,24 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
await statsSvc.ClientStatSvc.SaveChangesAsync(); await statsSvc.ClientStatSvc.SaveChangesAsync();
// increment the total play time // increment the total play time
serverStats.TotalPlayTime += (int)(DateTime.UtcNow - pl.LastConnection).TotalSeconds; 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> /// <summary>
/// Process stats for kill event /// Process stats for kill event
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task AddScriptKill(Player attacker, Player victim, int serverId, string map, string hitLoc, string type, 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 damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, string snapAngles)
{ {
var statsSvc = ContextThreads[serverId]; var statsSvc = ContextThreads[serverId];
Vector3 vDeathOrigin = null; Vector3 vDeathOrigin = null;
@ -235,6 +248,22 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
return; 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() var kill = new EFClientKill()
{ {
Active = true, Active = true,
@ -250,9 +279,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)), Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName)),
ViewAngles = vViewAngles, ViewAngles = vViewAngles,
TimeOffset = Int64.Parse(offset), TimeOffset = Int64.Parse(offset),
When = DateTime.UtcNow, When = time,
IsKillstreakKill = isKillstreakKill[0] != '0', IsKillstreakKill = isKillstreakKill[0] != '0',
AdsPercent = float.Parse(Ads) AdsPercent = float.Parse(Ads),
AnglesList = snapshotAngles
}; };
if (kill.DeathType == IW4Info.MeansOfDeath.MOD_SUICIDE && 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; clientStats.HitLocations.Single(hl => hl.Location == kill.HitLoc).HitCount += 1;
statsSvc.ClientStatSvc.Update(clientStats); statsSvc.ClientStatSvc.Update(clientStats);
await statsSvc.ClientStatSvc.SaveChangesAsync(); // await statsSvc.ClientStatSvc.SaveChangesAsync();
} }
//statsSvc.KillStatsSvc.Insert(kill); //statsSvc.KillStatsSvc.Insert(kill);
@ -290,6 +320,12 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
async Task executePenalty(Cheat.DetectionPenaltyResult penalty) async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
{ {
// prevent multiple bans from occuring
if (attacker.Level == Player.Permission.Banned)
{
return;
}
switch (penalty.ClientPenalty) switch (penalty.ClientPenalty)
{ {
case Penalty.PenaltyType.Ban: case Penalty.PenaltyType.Ban:
@ -312,6 +348,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
await executePenalty(clientDetection.ProcessKill(kill)); await executePenalty(clientDetection.ProcessKill(kill));
await executePenalty(clientDetection.ProcessTotalRatio(clientStats)); 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) 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; return;
} }
@ -338,7 +380,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
catch (KeyNotFoundException) 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; return;
} }
@ -393,7 +435,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
var statsSvc = ContextThreads[serverId]; var statsSvc = ContextThreads[serverId];
statsSvc.ClientStatSvc.Update(attackerStats); statsSvc.ClientStatSvc.Update(attackerStats);
statsSvc.ClientStatSvc.Update(victimStats); statsSvc.ClientStatSvc.Update(victimStats);
await statsSvc.ClientStatSvc.SaveChangesAsync(); //await statsSvc.ClientStatSvc.SaveChangesAsync();
} }
/// <summary> /// <summary>
@ -451,6 +493,11 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
// calculate the players Score Per Minute for the current session // calculate the players Score Per Minute for the current session
int scoreDifference = clientStats.RoundScore - clientStats.LastScore; int scoreDifference = clientStats.RoundScore - clientStats.LastScore;
// todo: fix the SPM for TEAMDAMAGE
if (scoreDifference < 0)
scoreDifference = clientStats.RoundScore;
double killSPM = scoreDifference / timeSinceLastCalc; double killSPM = scoreDifference / timeSinceLastCalc;
// calculate how much the KDR should weigh // calculate how much the KDR should weigh

View File

@ -4,6 +4,7 @@ using SharedLibraryCore.Database.Models;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
namespace IW4MAdmin.Plugins.Stats.Models namespace IW4MAdmin.Plugins.Stats.Models
{ {
@ -38,5 +39,7 @@ namespace IW4MAdmin.Plugins.Stats.Models
public bool IsKillstreakKill { get; set; } public bool IsKillstreakKill { get; set; }
[NotMapped] [NotMapped]
public float AdsPercent { get; set; } public float AdsPercent { get; set; }
[NotMapped]
public List<Vector3> AnglesList { get; set; }
} }
} }

View File

@ -36,6 +36,8 @@ namespace IW4MAdmin.Plugins.Stats.Models
public double Skill { get; set; } public double Skill { get; set; }
[Required] [Required]
public int TimePlayed { get; set; } public int TimePlayed { get; set; }
[Required]
public double MaxStrain { get; set; }
[NotMapped] [NotMapped]
public float AverageHitOffset public float AverageHitOffset

View File

@ -14,6 +14,9 @@ namespace IW4MAdmin.Plugins.Stats.Models
public int HitCount { get; set; } public int HitCount { get; set; }
[Required] [Required]
public float HitOffsetAverage { get; set; } public float HitOffsetAverage { get; set; }
[Required]
public float MaxAngleDistance { get; set; }
[Required]
public int ClientId { get; set; } public int ClientId { get; set; }
[ForeignKey("ClientId"), Column(Order = 0 )] [ForeignKey("ClientId"), Column(Order = 0 )]
public EFClient Client { get; set; } public EFClient Client { get; set; }

View File

@ -74,13 +74,16 @@ namespace IW4MAdmin.Plugins.Stats
case GameEvent.EventType.Kill: case GameEvent.EventType.Kill:
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback) 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], 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[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13]);
else if (!E.Owner.CustomCallback) else if (!E.Owner.CustomCallback)
await Manager.AddStandardKill(E.Origin, E.Target); await Manager.AddStandardKill(E.Origin, E.Target);
break; break;
case GameEvent.EventType.Death: case GameEvent.EventType.Death:
break; 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 abdomenRatio = 0;
double chestAbdomenRatio = 0; double chestAbdomenRatio = 0;
double hitOffsetAverage = 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) if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
{ {
@ -197,9 +202,21 @@ namespace IW4MAdmin.Plugins.Stats
new ProfileMeta() new ProfileMeta()
{ {
Key = "Hit Offset Average", Key = "Hit Offset Average",
Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°", Value = $"{Math.Round(((float)hitOffsetAverage), 4)}°",
Sensitive = true 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
}*/
}; };
} }

View File

@ -1,7 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Database; using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Exceptions;
using SharedLibraryCore.Objects; using SharedLibraryCore.Objects;
using SharedLibraryCore.Services; using SharedLibraryCore.Services;
using System; using System;
@ -36,6 +35,8 @@ namespace SharedLibraryCore.Commands
{ {
E.Origin.Level = Player.Permission.Owner; E.Origin.Level = Player.Permission.Owner;
await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_SUCCESS"]); 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); await E.Owner.Manager.GetClientService().Update(E.Origin);
} }
else else

View File

@ -1,7 +1,4 @@
using System; using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using SharedLibraryCore.Objects; using SharedLibraryCore.Objects;
@ -50,14 +47,16 @@ namespace SharedLibraryCore
Target = T; Target = T;
Owner = S; Owner = S;
OnProcessed = new ManualResetEventSlim(); OnProcessed = new ManualResetEventSlim();
Time = DateTime.UtcNow;
} }
public GameEvent() public GameEvent()
{ {
OnProcessed = new ManualResetEventSlim(); 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() var newEvent = new GameEvent()
{ {
@ -69,11 +68,12 @@ namespace SharedLibraryCore
Owner = e.Owner, Owner = e.Owner,
Remote = e.Remote, Remote = e.Remote,
Target = e.Target, Target = e.Target,
Type = newType Type = newType,
}; };
// hack: prevent the previous event from completing until this one is done // hack: prevent the previous event from completing until this one is done
e.OnProcessed = new ManualResetEventSlim(); e.OnProcessed = new ManualResetEventSlim();
newEvent.Time = e.Time;
return newEvent; return newEvent;
} }
@ -87,5 +87,6 @@ namespace SharedLibraryCore
public Boolean Remote = false; public Boolean Remote = false;
public object Extra { get; set; } public object Extra { get; set; }
public ManualResetEventSlim OnProcessed { get; set; } public ManualResetEventSlim OnProcessed { get; set; }
public DateTime Time { get; private set; }
} }
} }

View File

@ -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)); 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 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); public double DotProduct(Vector3 a) => (a.X * this.X) + (a.Y * this.Y) + (a.Z * this.Z);

View 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
}
}
}

View 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");
}
}
}

View 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
}
}
}

View File

@ -1,6 +1,7 @@
using SharedLibraryCore.Exceptions; using SharedLibraryCore.Exceptions;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using System; using System;
using System.Collections.Concurrent;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; 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 class Connection
{ {
public IPEndPoint Endpoint { get; private set; } public IPEndPoint Endpoint { get; private set; }
public string RConPassword { get; private set; } public string RConPassword { get; private set; }
Socket ServerConnection; public ConcurrentQueue<ManualResetEventSlim> ResponseQueue;
//Socket ServerConnection;
ILogger Log; ILogger Log;
int FailedSends; int FailedSends;
int FailedReceives; int FailedReceives;
@ -56,27 +77,13 @@ namespace SharedLibraryCore.RCon
OnConnected = new ManualResetEvent(false); OnConnected = new ManualResetEvent(false);
OnSent = new ManualResetEvent(false); OnSent = new ManualResetEvent(false);
OnReceived = 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() ~Connection()
{ {
ServerConnection.Shutdown(SocketShutdown.Both); /*ServerConnection.Shutdown(SocketShutdown.Both);
ServerConnection.Close(); ServerConnection.Close();
ServerConnection.Dispose(); ServerConnection.Dispose();*/
} }
private void OnConnectedCallback(IAsyncResult ar) private void OnConnectedCallback(IAsyncResult ar)
@ -106,8 +113,9 @@ namespace SharedLibraryCore.RCon
{ {
int sentByteNum = serverConnection.EndSend(ar); int sentByteNum = serverConnection.EndSend(ar);
#if DEBUG #if DEBUG
Log.WriteDebug($"Sent {sentByteNum} bytes to {ServerConnection.RemoteEndPoint}"); Log.WriteDebug($"Sent {sentByteNum} bytes to {serverConnection.RemoteEndPoint}");
#endif #endif
// this is where we override our await to make it
OnSent.Set(); OnSent.Set();
} }
@ -128,7 +136,7 @@ namespace SharedLibraryCore.RCon
if (bytesRead > 0) if (bytesRead > 0)
{ {
#if DEBUG #if DEBUG
Log.WriteDebug($"Received {bytesRead} bytes from {ServerConnection.RemoteEndPoint}"); Log.WriteDebug($"Received {bytesRead} bytes from {serverConnection.RemoteEndPoint}");
#endif #endif
FailedReceives = 0; FailedReceives = 0;
connectionState.ResponseString.Append(Utilities.EncodingType.GetString(connectionState.Buffer, 0, bytesRead).TrimEnd('\0') + '\n'); connectionState.ResponseString.Append(Utilities.EncodingType.GetString(connectionState.Buffer, 0, bytesRead).TrimEnd('\0') + '\n');
@ -138,7 +146,7 @@ namespace SharedLibraryCore.RCon
if (serverConnection.Available > 0) 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); new AsyncCallback(OnReceivedCallback), connectionState);
} }
else 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) public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "", bool waitForResponse = true)
{ {
// will this really prevent flooding? // 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; LastQuery = DateTime.Now;
@ -191,29 +204,37 @@ namespace SharedLibraryCore.RCon
break; break;
} }
using (var socketConnection = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
{
socketConnection.BeginConnect(Endpoint, new AsyncCallback(OnConnectedCallback), socketConnection);
retrySend: retrySend:
try 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)); bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
if (!success) if (!success)
{ {
FailedSends++; FailedSends++;
#if DEBUG #if DEBUG
Log.WriteDebug($"{FailedSends} failed sends to {ServerConnection.RemoteEndPoint.ToString()}"); Log.WriteDebug($"{FailedSends} failed sends to {socketConnection.RemoteEndPoint.ToString()}");
#endif #endif
if (FailedSends < 4) if (FailedSends < 4)
goto retrySend; goto retrySend;
else if (FailedSends == 4) else if (FailedSends == 4)
Log.WriteError($"Failed to send data to {ServerConnection.RemoteEndPoint}"); Log.WriteError($"Failed to send data to {socketConnection.RemoteEndPoint}");
} }
else else
{ {
if (FailedSends >= 4) if (FailedSends >= 4)
{ {
Log.WriteVerbose($"Resumed send RCon connection with {ServerConnection.RemoteEndPoint}"); Log.WriteVerbose($"Resumed send RCon connection with {socketConnection.RemoteEndPoint}");
FailedSends = 0; FailedSends = 0;
} }
} }
@ -230,12 +251,12 @@ namespace SharedLibraryCore.RCon
if (!waitForResponse) if (!waitForResponse)
return await Task.FromResult(new string[] { "" }); return await Task.FromResult(new string[] { "" });
var connectionState = new ConnectionState(ServerConnection); var connectionState = new ConnectionState(socketConnection);
retryReceive: retryReceive:
try try
{ {
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0, socketConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
new AsyncCallback(OnReceivedCallback), connectionState); new AsyncCallback(OnReceivedCallback), connectionState);
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout)); bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
@ -244,18 +265,18 @@ namespace SharedLibraryCore.RCon
FailedReceives++; FailedReceives++;
#if DEBUG #if DEBUG
Log.WriteDebug($"{FailedReceives} failed receives from {ServerConnection.RemoteEndPoint.ToString()}"); Log.WriteDebug($"{FailedReceives} failed receives from {socketConnection.RemoteEndPoint.ToString()}");
#endif #endif
if (FailedReceives < 4) if (FailedReceives < 4)
goto retrySend; goto retrySend;
else if (FailedReceives == 4) 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) 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) if (FailedReceives >= 4)
{ {
Log.WriteVerbose($"Resumed receive RCon connection from {ServerConnection.RemoteEndPoint}"); Log.WriteVerbose($"Resumed receive RCon connection from {socketConnection.RemoteEndPoint}");
FailedReceives = 0; FailedReceives = 0;
} }
} }
@ -282,7 +303,7 @@ namespace SharedLibraryCore.RCon
else if (FailedReceives == 4) 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) if (FailedReceives >= 4)
@ -307,3 +328,4 @@ namespace SharedLibraryCore.RCon
} }
} }
} }
}

View File

@ -13,6 +13,6 @@ namespace SharedLibraryCore.RCon
} }
public static char SeperatorChar = (char)int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier); 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);
} }
} }

View File

@ -12,6 +12,10 @@
<Configurations>Debug;Release;Prerelease</Configurations> <Configurations>Debug;Release;Prerelease</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Migrations\20180502195240_Update.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.2" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.2" />

View File

@ -28,7 +28,6 @@ namespace WebfrontCore.Controllers
public async Task<IActionResult> ExecuteAsync(int serverId, string command) public async Task<IActionResult> ExecuteAsync(int serverId, string command)
{ {
var server = Manager.GetServers().First(s => s.GetHashCode() == serverId); var server = Manager.GetServers().First(s => s.GetHashCode() == serverId);
var client = new Player() var client = new Player()
{ {
@ -50,7 +49,7 @@ namespace WebfrontCore.Controllers
Manager.GetEventHandler().AddEvent(remoteEvent); Manager.GetEventHandler().AddEvent(remoteEvent);
// wait for the event to process // 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(); var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
// remove the added command response // remove the added command response

View File

@ -22,6 +22,10 @@
<Configurations>Debug;Release;Prerelease</Configurations> <Configurations>Debug;Release;Prerelease</Configurations>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Remove="bower.json" /> <Content Remove="bower.json" />
<Content Remove="bundleconfig.json" /> <Content Remove="bundleconfig.json" />