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" />
|
<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>
|
||||||
|
@ -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()
|
||||||
|
@ -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");
|
||||||
|
@ -117,9 +117,12 @@ namespace IW4MAdmin.Application
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Origin.CurrentServer = ServerManager.Servers[0];
|
if (userInput?.Length > 0)
|
||||||
GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]);
|
{
|
||||||
ServerManager.GetEventHandler().AddEvent(E);
|
Origin.CurrentServer = ServerManager.Servers[0];
|
||||||
|
GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]);
|
||||||
|
ServerManager.GetEventHandler().AddEvent(E);
|
||||||
|
}
|
||||||
Console.Write('>');
|
Console.Write('>');
|
||||||
|
|
||||||
} while (ServerManager.Running);
|
} while (ServerManager.Running);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,11 +527,20 @@ 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
|
||||||
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname };
|
{
|
||||||
|
|
||||||
|
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
|
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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
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 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 };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
@ -197,23 +201,32 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue3);
|
playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue3);
|
||||||
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
|
detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue4);
|
||||||
|
|
||||||
/* // sync their stats before they leave
|
/* // sync their stats before they leave
|
||||||
clientStats = UpdateStats(clientStats);*/
|
clientStats = UpdateStats(clientStats);*/
|
||||||
|
|
||||||
// todo: should this be saved every disconnect?
|
// todo: should this be saved every disconnect?
|
||||||
statsSvc.ClientStatSvc.Update(clientStats);
|
statsSvc.ClientStatSvc.Update(clientStats);
|
||||||
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
|
||||||
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
@ -172,9 +177,9 @@ namespace IW4MAdmin.Plugins.Stats
|
|||||||
{
|
{
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "Chest Ratio",
|
Key = "Chest Ratio",
|
||||||
Value = chestRatio,
|
Value = chestRatio,
|
||||||
Sensitive = true
|
Sensitive = true
|
||||||
},
|
},
|
||||||
new ProfileMeta()
|
new ProfileMeta()
|
||||||
{
|
{
|
||||||
@ -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
|
||||||
|
}*/
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
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.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,119 +204,128 @@ namespace SharedLibraryCore.RCon
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
retrySend:
|
using (var socketConnection = new Socket(Endpoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp))
|
||||||
try
|
|
||||||
{
|
{
|
||||||
ServerConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), ServerConnection);
|
socketConnection.BeginConnect(Endpoint, new AsyncCallback(OnConnectedCallback), socketConnection);
|
||||||
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
|
||||||
|
|
||||||
if (!success)
|
retrySend:
|
||||||
|
try
|
||||||
{
|
{
|
||||||
FailedSends++;
|
|
||||||
#if DEBUG
|
|
||||||
Log.WriteDebug($"{FailedSends} failed sends to {ServerConnection.RemoteEndPoint.ToString()}");
|
|
||||||
#endif
|
|
||||||
if (FailedSends < 4)
|
|
||||||
goto retrySend;
|
|
||||||
else if (FailedSends == 4)
|
|
||||||
Log.WriteError($"Failed to send data to {ServerConnection.RemoteEndPoint}");
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout))
|
||||||
{
|
throw new SocketException((int)SocketError.TimedOut);
|
||||||
if (FailedSends >= 4)
|
|
||||||
|
socketConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), socketConnection);
|
||||||
|
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
||||||
|
|
||||||
|
if (!success)
|
||||||
{
|
{
|
||||||
Log.WriteVerbose($"Resumed send RCon connection with {ServerConnection.RemoteEndPoint}");
|
FailedSends++;
|
||||||
FailedSends = 0;
|
#if DEBUG
|
||||||
|
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 {socketConnection.RemoteEndPoint}");
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FailedSends >= 4)
|
||||||
|
{
|
||||||
|
Log.WriteVerbose($"Resumed send RCon connection with {socketConnection.RemoteEndPoint}");
|
||||||
|
FailedSends = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
|
||||||
// this result is normal if the server is not listening
|
|
||||||
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
|
||||||
e.NativeErrorCode != (int)SocketError.TimedOut)
|
|
||||||
throw new NetworkException($"Unexpected error while sending data to server - {e.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!waitForResponse)
|
|
||||||
return await Task.FromResult(new string[] { "" });
|
|
||||||
|
|
||||||
var connectionState = new ConnectionState(ServerConnection);
|
|
||||||
|
|
||||||
retryReceive:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
|
||||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
|
||||||
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
{
|
||||||
|
// this result is normal if the server is not listening
|
||||||
|
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
||||||
|
e.NativeErrorCode != (int)SocketError.TimedOut)
|
||||||
|
throw new NetworkException($"Unexpected error while sending data to server - {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
FailedReceives++;
|
if (!waitForResponse)
|
||||||
|
return await Task.FromResult(new string[] { "" });
|
||||||
|
|
||||||
|
var connectionState = new ConnectionState(socketConnection);
|
||||||
|
|
||||||
|
retryReceive:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socketConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||||
|
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||||
|
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
Log.WriteError($"Failed to receive data from {socketConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FailedReceives >= 4)
|
||||||
|
{
|
||||||
|
throw new NetworkException($"Could not receive data from {socketConnection.RemoteEndPoint}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FailedReceives >= 4)
|
||||||
|
{
|
||||||
|
Log.WriteVerbose($"Resumed receive RCon connection from {socketConnection.RemoteEndPoint}");
|
||||||
|
FailedReceives = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
// this result is normal if the server is not listening
|
||||||
|
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
||||||
|
e.NativeErrorCode != (int)SocketError.TimedOut)
|
||||||
|
throw new NetworkException($"Unexpected error while receiving data from server - {e.Message}");
|
||||||
|
else if (FailedReceives < 4)
|
||||||
|
{
|
||||||
|
goto retryReceive;
|
||||||
|
}
|
||||||
|
|
||||||
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(e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
string queryResponse = response;
|
||||||
|
|
||||||
|
if (queryResponse.Contains("Invalid password"))
|
||||||
|
throw new NetworkException("RCON password is invalid");
|
||||||
|
if (queryResponse.ToString().Contains("rcon_password"))
|
||||||
|
throw new NetworkException("RCON password has not been set");
|
||||||
|
|
||||||
|
string[] splitResponse = queryResponse.Split(new char[]
|
||||||
{
|
{
|
||||||
if (FailedReceives >= 4)
|
|
||||||
{
|
|
||||||
Log.WriteVerbose($"Resumed receive RCon connection from {ServerConnection.RemoteEndPoint}");
|
|
||||||
FailedReceives = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (SocketException e)
|
|
||||||
{
|
|
||||||
// this result is normal if the server is not listening
|
|
||||||
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
|
||||||
e.NativeErrorCode != (int)SocketError.TimedOut)
|
|
||||||
throw new NetworkException($"Unexpected error while receiving data from server - {e.Message}");
|
|
||||||
else if (FailedReceives < 4)
|
|
||||||
{
|
|
||||||
goto retryReceive;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (FailedReceives == 4)
|
|
||||||
{
|
|
||||||
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint} after {FailedReceives} tries");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FailedReceives >= 4)
|
|
||||||
{
|
|
||||||
throw new NetworkException(e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string queryResponse = response;
|
|
||||||
|
|
||||||
if (queryResponse.Contains("Invalid password"))
|
|
||||||
throw new NetworkException("RCON password is invalid");
|
|
||||||
if (queryResponse.ToString().Contains("rcon_password"))
|
|
||||||
throw new NetworkException("RCON password has not been set");
|
|
||||||
|
|
||||||
string[] splitResponse = queryResponse.Split(new char[]
|
|
||||||
{
|
|
||||||
'\n'
|
'\n'
|
||||||
}, StringSplitOptions.RemoveEmptyEntries)
|
}, StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Select(line => line.Trim()).ToArray();
|
.Select(line => line.Trim()).ToArray();
|
||||||
return splitResponse;
|
return splitResponse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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" />
|
||||||
|
@ -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
|
||||||
|
@ -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" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user