kick clients with default name or an inuse name
fixed regular expression not being escaped when matching names fixed reset stats fixed duplicate kills
This commit is contained in:
parent
442569b339
commit
52cc5a30e6
@ -405,7 +405,6 @@ copy /Y "$(SolutionDir)_customcallbacks.gsc" "$(SolutionDir)BUILD\userraw\script
|
|||||||
|
|
||||||
copy /Y "$(TargetDir)$(TargetName).exe" "$(SolutionDir)BUILD"
|
copy /Y "$(TargetDir)$(TargetName).exe" "$(SolutionDir)BUILD"
|
||||||
copy /Y "$(TargetDir)IW4MAdmin.exe.config" "$(SolutionDir)BUILD"
|
copy /Y "$(TargetDir)IW4MAdmin.exe.config" "$(SolutionDir)BUILD"
|
||||||
copy /Y "$(ProjectDir)lib\Kayak.dll" "$(SolutionDir)BUILD\lib"
|
|
||||||
xcopy /Y /I /E "$(SolutionDir)SharedLibrary\$(OutDir)*" "$(SolutionDir)Admin\Lib"
|
xcopy /Y /I /E "$(SolutionDir)SharedLibrary\$(OutDir)*" "$(SolutionDir)Admin\Lib"
|
||||||
|
|
||||||
xcopy /Y /I /E "$(ProjectDir)webfront\*" "$(SolutionDir)BUILD\Webfront"
|
xcopy /Y /I /E "$(ProjectDir)webfront\*" "$(SolutionDir)BUILD\Webfront"
|
||||||
@ -418,7 +417,8 @@ if $(ConfigurationName) == Release-Stable powershell.exe -file "$(SolutionDir)DE
|
|||||||
</PostBuildEvent>
|
</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PreBuildEvent>xcopy /Y "$(SolutionDir)BUILD\Plugins" "$(TargetDir)Plugins\"</PreBuildEvent>
|
<PreBuildEvent>
|
||||||
|
</PreBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
@ -47,6 +47,19 @@ namespace IW4MAdmin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Players.FirstOrDefault(p => p != null && p.Name == polledPlayer.Name) != null)
|
||||||
|
{
|
||||||
|
await this.ExecuteCommandAsync($"clientkick {polledPlayer.ClientNumber} \"Your name is being used by someone else.\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (polledPlayer.Name == "Unknown Soldier" ||
|
||||||
|
polledPlayer.Name == "UnknownSoldier")
|
||||||
|
{
|
||||||
|
await this.ExecuteCommandAsync($"clientkick {polledPlayer.ClientNumber} \"Please change your name using /name.\"");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Logger.WriteDebug($"Client slot #{polledPlayer.ClientNumber} now reserved");
|
Logger.WriteDebug($"Client slot #{polledPlayer.ClientNumber} now reserved");
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -65,10 +78,10 @@ namespace IW4MAdmin
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
client.Connections += 1;
|
client.Connections += 1;
|
||||||
bool aliasExists = client.AliasLink.Children
|
var existingAlias = client.AliasLink.Children
|
||||||
.FirstOrDefault(a => a.Name == polledPlayer.Name && a.IPAddress == polledPlayer.IPAddress) != null;
|
.FirstOrDefault(a => a.Name == polledPlayer.Name && a.IPAddress == polledPlayer.IPAddress);
|
||||||
|
|
||||||
if (!aliasExists)
|
if (existingAlias == null)
|
||||||
{
|
{
|
||||||
Logger.WriteDebug($"Client {polledPlayer} has connected previously under a different ip/name");
|
Logger.WriteDebug($"Client {polledPlayer} has connected previously under a different ip/name");
|
||||||
client.CurrentAlias = new SharedLibrary.Database.Models.EFAlias()
|
client.CurrentAlias = new SharedLibrary.Database.Models.EFAlias()
|
||||||
@ -82,6 +95,12 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
await Manager.GetClientService().Update(client);
|
await Manager.GetClientService().Update(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (existingAlias.Name == polledPlayer.Name)
|
||||||
|
{
|
||||||
|
client.CurrentAlias = existingAlias;
|
||||||
|
await Manager.GetClientService().Update(client);
|
||||||
|
}
|
||||||
player = client.AsPlayer();
|
player = client.AsPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +271,7 @@ namespace IW4MAdmin
|
|||||||
else if (matchingPlayers.Count == 1)
|
else if (matchingPlayers.Count == 1)
|
||||||
{
|
{
|
||||||
E.Target = matchingPlayers.First();
|
E.Target = matchingPlayers.First();
|
||||||
E.Data = Regex.Replace(E.Data, $"\"{E.Target.Name}\"", "", RegexOptions.IgnoreCase).Trim();
|
E.Data = Regex.Replace(E.Data, Regex.Escape($"\"{E.Target.Name}\""), "", RegexOptions.IgnoreCase).Trim();
|
||||||
|
|
||||||
if ((E.Data.ToLower().Trim() == E.Target.Name.ToLower().Trim() ||
|
if ((E.Data.ToLower().Trim() == E.Target.Name.ToLower().Trim() ||
|
||||||
E.Data == String.Empty) &&
|
E.Data == String.Empty) &&
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>EventAPI</RootNamespace>
|
<RootNamespace>EventAPI</RootNamespace>
|
||||||
<AssemblyName>EventAPI</AssemblyName>
|
<AssemblyName>EventAPI</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using SharedLibrary;
|
using SharedLibrary;
|
||||||
@ -9,61 +8,6 @@ using SharedLibrary.Objects;
|
|||||||
|
|
||||||
namespace EventAPI
|
namespace EventAPI
|
||||||
{
|
{
|
||||||
class EventsJSON : IPage
|
|
||||||
{
|
|
||||||
private struct EventResponse
|
|
||||||
{
|
|
||||||
public int eventCount;
|
|
||||||
public RestEvent Event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetName()
|
|
||||||
{
|
|
||||||
return "Events";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetPath()
|
|
||||||
{
|
|
||||||
return "/api/events";
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<HttpResponse> GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
|
||||||
{
|
|
||||||
bool shouldQuery = querySet.Get("status") != null;
|
|
||||||
EventResponse requestedEvent = new EventResponse();
|
|
||||||
HttpResponse resp = new HttpResponse();
|
|
||||||
|
|
||||||
if (shouldQuery)
|
|
||||||
{
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
foreach (var S in Events.ActiveServers)
|
|
||||||
s.Append(String.Format("{0} has {1}/{4} players playing {2} on {3}\n", S.Hostname, S.GetPlayersAsList().Count, Utilities.GetLocalizedGametype(S.Gametype), S.CurrentMap.Name, S.MaxClients));
|
|
||||||
requestedEvent.Event = new RestEvent(RestEvent.EventType.STATUS, RestEvent.EventVersion.IW4MAdmin, s.ToString(), "Status", "", "");
|
|
||||||
requestedEvent.eventCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (Events.APIEvents.Count > 0)
|
|
||||||
{
|
|
||||||
requestedEvent.Event = Events.APIEvents.Dequeue();
|
|
||||||
requestedEvent.eventCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
requestedEvent.eventCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedEvent);
|
|
||||||
resp.contentType = GetContentType();
|
|
||||||
resp.additionalHeaders = new Dictionary<string, string>();
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetContentType() => "application/json";
|
|
||||||
|
|
||||||
public bool Visible() => false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Events : IPlugin
|
class Events : IPlugin
|
||||||
{
|
{
|
||||||
public static Queue<RestEvent> APIEvents { get; private set; }
|
public static Queue<RestEvent> APIEvents { get; private set; }
|
||||||
@ -84,7 +28,6 @@ namespace EventAPI
|
|||||||
APIEvents = new Queue<RestEvent>();
|
APIEvents = new Queue<RestEvent>();
|
||||||
flaggedMessagesText = new List<string>();
|
flaggedMessagesText = new List<string>();
|
||||||
ActiveServers = new List<Server>();
|
ActiveServers = new List<Server>();
|
||||||
WebService.PageList.Add(new EventsJSON());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnUnloadAsync()
|
public async Task OnUnloadAsync()
|
||||||
@ -107,8 +50,7 @@ namespace EventAPI
|
|||||||
|
|
||||||
if (E.Type == Event.GType.Stop)
|
if (E.Type == Event.GType.Stop)
|
||||||
{
|
{
|
||||||
// fixme: this will be bad once FTP is working and there can be multiple servers on the same port.
|
ActiveServers.RemoveAll(s => s.GetHashCode() == S.GetHashCode());
|
||||||
ActiveServers.RemoveAll(s => s.GetPort() == S.GetPort());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (E.Type == Event.GType.Connect)
|
if (E.Type == Event.GType.Connect)
|
||||||
|
91
Plugins/SimpleStats/Cheat/Detection.cs
Normal file
91
Plugins/SimpleStats/Cheat/Detection.cs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
using SharedLibrary.Interfaces;
|
||||||
|
using StatsPlugin.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace StatsPlugin.Cheat
|
||||||
|
{
|
||||||
|
class Detection
|
||||||
|
{
|
||||||
|
int Kills;
|
||||||
|
int AboveThresholdCount;
|
||||||
|
double AverageKillTime;
|
||||||
|
Dictionary<IW4Info.HitLocation, int> HitLocationCount;
|
||||||
|
DateTime LastKill;
|
||||||
|
ILogger Log;
|
||||||
|
|
||||||
|
public Detection(ILogger log)
|
||||||
|
{
|
||||||
|
Log = log;
|
||||||
|
HitLocationCount = new Dictionary<IW4Info.HitLocation, int>();
|
||||||
|
foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation)))
|
||||||
|
HitLocationCount.Add((IW4Info.HitLocation)loc, 0);
|
||||||
|
LastKill = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Analyze kill and see if performed by a cheater
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="kill">kill performed by the player</param>
|
||||||
|
/// <returns>true if detection reached thresholds, false otherwise</returns>
|
||||||
|
public bool ProcessKill(EFClientKill kill)
|
||||||
|
{
|
||||||
|
if (kill.DeathType != IW4Info.MeansOfDeath.MOD_PISTOL_BULLET && kill.DeathType != IW4Info.MeansOfDeath.MOD_RIFLE_BULLET)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool thresholdReached = false;
|
||||||
|
|
||||||
|
HitLocationCount[kill.HitLoc]++;
|
||||||
|
Kills++;
|
||||||
|
AverageKillTime = (AverageKillTime + (DateTime.UtcNow - LastKill).TotalSeconds) / Kills;
|
||||||
|
|
||||||
|
if (Kills > Thresholds.LowSampleMinKills)
|
||||||
|
{
|
||||||
|
double marginOfError = Thresholds.GetMarginOfError(Kills);
|
||||||
|
// determine what the max headshot percentage can be for current number of kills
|
||||||
|
double lerpAmount = Math.Min(1.0, (Kills - Thresholds.LowSampleMinKills) / (double)(Thresholds.HighSampleMinKills - Thresholds.LowSampleMinKills));
|
||||||
|
double maxHeadshotLerpValue = Thresholds.Lerp( Thresholds.HeadshotRatioThresholdLowSample, Thresholds.HeadshotRatioThresholdHighSample, lerpAmount);
|
||||||
|
// determine what the max bone percentage can be for current number of kills
|
||||||
|
double maxBoneRatioLerpValue = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample, Thresholds.BoneRatioThresholdHighSample, lerpAmount);
|
||||||
|
// calculate headshot ratio
|
||||||
|
double headshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet]) / (double)Kills) - marginOfError;
|
||||||
|
// calculate maximum bone
|
||||||
|
double maximumBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max()) - marginOfError;
|
||||||
|
|
||||||
|
if (headshotRatio > maxHeadshotLerpValue)
|
||||||
|
{
|
||||||
|
AboveThresholdCount++;
|
||||||
|
Log.WriteDebug("**Maximum Headshot Ratio Reached**");
|
||||||
|
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||||
|
Log.WriteDebug($"**Kills: {Kills}");
|
||||||
|
Log.WriteDebug($"**Ratio {headshotRatio}");
|
||||||
|
Log.WriteDebug($"**MaxRatio {maxHeadshotLerpValue}");
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var kvp in HitLocationCount)
|
||||||
|
sb.Append($"HitLocation: {kvp.Key} Count: {kvp.Value}");
|
||||||
|
Log.WriteDebug(sb.ToString());
|
||||||
|
Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}");
|
||||||
|
thresholdReached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (maximumBoneRatio > maxBoneRatioLerpValue)
|
||||||
|
{
|
||||||
|
Log.WriteDebug("**Maximum Bone Ratio Reached**");
|
||||||
|
Log.WriteDebug($"ClientId: {kill.AttackerId}");
|
||||||
|
Log.WriteDebug($"**Kills: {Kills}");
|
||||||
|
Log.WriteDebug($"**Ratio {maximumBoneRatio}");
|
||||||
|
Log.WriteDebug($"**MaxRatio {maxBoneRatioLerpValue}");
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var kvp in HitLocationCount)
|
||||||
|
sb.Append($"HitLocation: {kvp.Key} Count: {kvp.Value}");
|
||||||
|
Log.WriteDebug(sb.ToString());
|
||||||
|
thresholdReached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return thresholdReached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
Plugins/SimpleStats/Cheat/Thresholds.cs
Normal file
37
Plugins/SimpleStats/Cheat/Thresholds.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace StatsPlugin.Cheat
|
||||||
|
{
|
||||||
|
class Thresholds
|
||||||
|
{
|
||||||
|
private const double Deviations = 3.33;
|
||||||
|
|
||||||
|
public const double HeadshotRatioThresholdLowSample = HeadshotRatioStandardDeviationLowSample * Deviations + HeadshotRatioMean;
|
||||||
|
public const double HeadshotRatioThresholdHighSample = HeadshotRatioStandardDeviationHighSample * Deviations + HeadshotRatioMean;
|
||||||
|
public const double HeadshotRatioStandardDeviationLowSample = 0.1769994181;
|
||||||
|
public const double HeadshotRatioStandardDeviationHighSample = 0.03924263235;
|
||||||
|
//public const double HeadshotRatioMean = 0.09587712258;
|
||||||
|
public const double HeadshotRatioMean = 0.222;
|
||||||
|
|
||||||
|
public const double BoneRatioThresholdLowSample = BoneRatioStandardDeviationLowSample * Deviations + BoneRatioMean;
|
||||||
|
public const double BoneRatioThresholdHighSample = BoneRatioStandardDeviationHighSample * Deviations + BoneRatioMean;
|
||||||
|
public const double BoneRatioStandardDeviationLowSample = 0.1324612879;
|
||||||
|
public const double BoneRatioStandardDeviationHighSample = 0.0515753935;
|
||||||
|
public const double BoneRatioMean = 0.3982907516;
|
||||||
|
|
||||||
|
public const int LowSampleMinKills = 15;
|
||||||
|
public const int HighSampleMinKills = 100;
|
||||||
|
public const double KillTimeThreshold = 0.2;
|
||||||
|
|
||||||
|
public static double GetMarginOfError(int numKills) => 1.645 /(2 * Math.Sqrt(numKills));
|
||||||
|
|
||||||
|
public static double Lerp(double v1, double v2, double amount)
|
||||||
|
{
|
||||||
|
return v1 + (v2 - v1) * amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ namespace StatsPlugin.Commands
|
|||||||
if (E.Origin.ClientNumber >= 0)
|
if (E.Origin.ClientNumber >= 0)
|
||||||
{
|
{
|
||||||
var svc = new SharedLibrary.Services.GenericRepository<EFClientStatistics>();
|
var svc = new SharedLibrary.Services.GenericRepository<EFClientStatistics>();
|
||||||
int serverId = E.Origin.GetHashCode();
|
int serverId = E.Owner.GetHashCode();
|
||||||
var stats = svc.Find(s => s.ClientId == E.Origin.ClientId && s.ServerId == serverId).First();
|
var stats = svc.Find(s => s.ClientId == E.Origin.ClientId && s.ServerId == serverId).First();
|
||||||
|
|
||||||
stats.Deaths = 0;
|
stats.Deaths = 0;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using SharedLibrary;
|
using SharedLibrary;
|
||||||
|
using StatsPlugin.Cheat;
|
||||||
using StatsPlugin.Models;
|
using StatsPlugin.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -8,15 +9,16 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace StatsPlugin.Helpers
|
namespace StatsPlugin.Helpers
|
||||||
{
|
{
|
||||||
public class ServerStats
|
class ServerStats {
|
||||||
{
|
|
||||||
public Dictionary<int, EFClientStatistics> PlayerStats { get; set; }
|
public Dictionary<int, EFClientStatistics> PlayerStats { get; set; }
|
||||||
|
public Dictionary<int, Detection> PlayerDetections { get; set; }
|
||||||
public EFServerStatistics ServerStatistics { get; private set; }
|
public EFServerStatistics ServerStatistics { get; private set; }
|
||||||
public EFServer Server { get; private set; }
|
public EFServer Server { get; private set; }
|
||||||
|
|
||||||
public ServerStats(EFServer sv, EFServerStatistics st)
|
public ServerStats(EFServer sv, EFServerStatistics st)
|
||||||
{
|
{
|
||||||
PlayerStats = new Dictionary<int, EFClientStatistics>();
|
PlayerStats = new Dictionary<int, EFClientStatistics>();
|
||||||
|
PlayerDetections = new Dictionary<int, Detection>();
|
||||||
ServerStatistics = st;
|
ServerStatistics = st;
|
||||||
Server = sv;
|
Server = sv;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,16 @@ namespace StatsPlugin.Helpers
|
|||||||
}
|
}
|
||||||
playerStats.Add(pl.ClientNumber, clientStats);
|
playerStats.Add(pl.ClientNumber, clientStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var detectionStats = Servers[serverId].PlayerDetections;
|
||||||
|
lock (detectionStats)
|
||||||
|
{
|
||||||
|
if (detectionStats.ContainsKey(pl.ClientNumber))
|
||||||
|
detectionStats.Remove(pl.ClientNumber);
|
||||||
|
|
||||||
|
detectionStats.Add(pl.ClientNumber, new Cheat.Detection(Log));
|
||||||
|
}
|
||||||
|
|
||||||
return clientStats;
|
return clientStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +145,7 @@ namespace StatsPlugin.Helpers
|
|||||||
{
|
{
|
||||||
int serverId = pl.CurrentServer.GetHashCode();
|
int serverId = pl.CurrentServer.GetHashCode();
|
||||||
var playerStats = Servers[serverId].PlayerStats;
|
var playerStats = Servers[serverId].PlayerStats;
|
||||||
|
var detectionStats = Servers[serverId].PlayerDetections;
|
||||||
var serverStats = Servers[serverId].ServerStatistics;
|
var serverStats = Servers[serverId].ServerStatistics;
|
||||||
var statsSvc = ContextThreads[serverId];
|
var statsSvc = ContextThreads[serverId];
|
||||||
|
|
||||||
@ -143,6 +154,8 @@ namespace StatsPlugin.Helpers
|
|||||||
// remove the client from the stats dictionary as they're leaving
|
// remove the client from the stats dictionary as they're leaving
|
||||||
lock (playerStats)
|
lock (playerStats)
|
||||||
playerStats.Remove(pl.ClientNumber);
|
playerStats.Remove(pl.ClientNumber);
|
||||||
|
lock (detectionStats)
|
||||||
|
detectionStats.Remove(pl.ClientNumber);
|
||||||
|
|
||||||
// sync their stats before they leave
|
// sync their stats before they leave
|
||||||
UpdateStats(clientStats);
|
UpdateStats(clientStats);
|
||||||
@ -163,8 +176,9 @@ namespace StatsPlugin.Helpers
|
|||||||
{
|
{
|
||||||
await AddStandardKill(attacker, victim);
|
await AddStandardKill(attacker, victim);
|
||||||
|
|
||||||
return;
|
|
||||||
var statsSvc = ContextThreads[serverId];
|
var statsSvc = ContextThreads[serverId];
|
||||||
|
var playerDetection = Servers[serverId].PlayerDetections[attacker.ClientNumber];
|
||||||
|
|
||||||
var kill = new EFClientKill()
|
var kill = new EFClientKill()
|
||||||
{
|
{
|
||||||
Active = true,
|
Active = true,
|
||||||
@ -180,6 +194,10 @@ namespace StatsPlugin.Helpers
|
|||||||
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName))
|
Weapon = ParseEnum<IW4Info.WeaponName>.Get(weapon, typeof(IW4Info.WeaponName))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
playerDetection.ProcessKill(kill);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
statsSvc.KillStatsSvc.Insert(kill);
|
statsSvc.KillStatsSvc.Insert(kill);
|
||||||
await statsSvc.KillStatsSvc.SaveChangesAsync();
|
await statsSvc.KillStatsSvc.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ namespace StatsPlugin
|
|||||||
await Manager.RemovePlayer(E.Origin);
|
await Manager.RemovePlayer(E.Origin);
|
||||||
break;
|
break;
|
||||||
case Event.GType.Say:
|
case Event.GType.Say:
|
||||||
if (E.Data != string.Empty && E.Data.Trim().Length > 0 && E.Data[0] != '!')
|
if (E.Data != string.Empty && E.Data.Trim().Length > 0 && E.Data.Trim()[0] != '!')
|
||||||
await Manager.AddMessageAsync(E.Origin.ClientId, E.Owner.GetHashCode(), E.Data);
|
await Manager.AddMessageAsync(E.Origin.ClientId, E.Owner.GetHashCode(), E.Data);
|
||||||
break;
|
break;
|
||||||
case Event.GType.MapChange:
|
case Event.GType.MapChange:
|
||||||
@ -69,9 +69,9 @@ namespace StatsPlugin
|
|||||||
break;
|
break;
|
||||||
case Event.GType.Kill:
|
case Event.GType.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"))
|
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback)
|
||||||
await Manager.AddScriptKill(E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8], killInfo[5], killInfo[6], killInfo[3], killInfo[4]);
|
await Manager.AddScriptKill(E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8], killInfo[5], killInfo[6], killInfo[3], killInfo[4]);
|
||||||
else
|
else if (!E.Owner.CustomCallback)
|
||||||
await Manager.AddStandardKill(E.Origin, E.Target);
|
await Manager.AddStandardKill(E.Origin, E.Target);
|
||||||
break;
|
break;
|
||||||
case Event.GType.Death:
|
case Event.GType.Death:
|
||||||
|
@ -118,6 +118,8 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Cheat\Detection.cs" />
|
||||||
|
<Compile Include="Cheat\Thresholds.cs" />
|
||||||
<Compile Include="Commands\ResetStats.cs" />
|
<Compile Include="Commands\ResetStats.cs" />
|
||||||
<Compile Include="Commands\TopStats.cs" />
|
<Compile Include="Commands\TopStats.cs" />
|
||||||
<Compile Include="Commands\ViewStats.cs" />
|
<Compile Include="Commands\ViewStats.cs" />
|
||||||
|
@ -740,7 +740,6 @@ namespace SharedLibrary.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
E.Data = E.Data.RemoveWords(1);
|
|
||||||
E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data));
|
E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data));
|
||||||
|
|
||||||
await E.Origin.Tell($"Thank you for your report, an administrator has been notified");
|
await E.Origin.Tell($"Thank you for your report, an administrator has been notified");
|
||||||
|
@ -8,12 +8,12 @@ by editing this MSBuild file. In order to learn more about this please visit htt
|
|||||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||||
<PublishProvider>FileSystem</PublishProvider>
|
<PublishProvider>FileSystem</PublishProvider>
|
||||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
<LastUsedPlatform>x86</LastUsedPlatform>
|
||||||
<SiteUrlToLaunchAfterPublish />
|
<SiteUrlToLaunchAfterPublish />
|
||||||
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
|
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
|
||||||
<ExcludeApp_Data>False</ExcludeApp_Data>
|
<ExcludeApp_Data>False</ExcludeApp_Data>
|
||||||
<ProjectGuid>65340d7d-5831-406c-acad-b13ba634bde2</ProjectGuid>
|
<ProjectGuid>65340d7d-5831-406c-acad-b13ba634bde2</ProjectGuid>
|
||||||
<publishUrl>bin\Release\PublishOutput</publishUrl>
|
<publishUrl>C:\Users\User\Desktop\stuff\IW4M-Admin\IW4M-Admin\WebfrontCore\bin\x86\Release\PublishOutput</publishUrl>
|
||||||
<DeleteExistingFiles>True</DeleteExistingFiles>
|
<DeleteExistingFiles>True</DeleteExistingFiles>
|
||||||
<TargetFramework>net452</TargetFramework>
|
<TargetFramework>net452</TargetFramework>
|
||||||
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
|
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
|
||||||
|
@ -63,4 +63,8 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
|
<Exec Command="xcopy /Y "$(SolutionDir)BUILD\Plugins" "$(TargetDir)Plugins\"" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user