lots of fixes :)

This commit is contained in:
RaidMax 2018-05-10 00:34:29 -05:00
parent 9ff7f39e8d
commit e964013700
21 changed files with 291 additions and 248 deletions

View File

@ -21,7 +21,7 @@ namespace IW4MAdmin.Application.EventParsers
{ {
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Script, Type = GameEvent.EventType.Kill,
Data = logLine, Data = logLine,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)), Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)), Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
@ -32,13 +32,27 @@ namespace IW4MAdmin.Application.EventParsers
if (cleanedEventLine == "say" || cleanedEventLine == "sayteam") if (cleanedEventLine == "say" || cleanedEventLine == "sayteam")
{ {
string message = lineSplit[4].Replace("\x15", "");
if (message[0] == '!' || message[1] == '@')
{
return new GameEvent()
{
Type = GameEvent.EventType.Command,
Data = message,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
Owner = server,
Message = message
};
}
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Say, Type = GameEvent.EventType.Say,
Data = lineSplit[4].Replace("\x15", ""), Data = message,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)), Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
Owner = server, Owner = server,
Message = lineSplit[4].Replace("\x15", "") Message = message
}; };
} }
@ -46,7 +60,7 @@ namespace IW4MAdmin.Application.EventParsers
{ {
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Script, Type = GameEvent.EventType.ScriptKill,
Data = logLine, Data = logLine,
Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()), Origin = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[1].ConvertLong()),
Target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong()), Target = server.GetPlayersAsList().First(c => c.NetworkId == lineSplit[2].ConvertLong()),

View File

@ -20,7 +20,7 @@ namespace IW4MAdmin.Application.EventParsers
{ {
return new GameEvent() return new GameEvent()
{ {
Type = GameEvent.EventType.Script, Type = GameEvent.EventType.Kill,
Data = cleanedEventLine, Data = cleanedEventLine,
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)), Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)), Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),

View File

@ -3,20 +3,23 @@ using SharedLibraryCore.Interfaces;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading;
namespace IW4MAdmin.Application namespace IW4MAdmin.Application
{ {
class GameEventHandler : IEventHandler class GameEventHandler : IEventHandler
{ {
private ConcurrentQueue<GameEvent> EventQueue; private ConcurrentQueue<GameEvent> EventQueue;
private ConcurrentQueue<GameEvent> StatusSensitiveQueue; private Queue<GameEvent> StatusSensitiveQueue;
private IManager Manager; private IManager Manager;
public GameEventHandler(IManager mgr) public GameEventHandler(IManager mgr)
{ {
EventQueue = new ConcurrentQueue<GameEvent>(); EventQueue = new ConcurrentQueue<GameEvent>();
StatusSensitiveQueue = new ConcurrentQueue<GameEvent>(); StatusSensitiveQueue = new Queue<GameEvent>();
Manager = mgr; Manager = mgr;
} }
@ -26,25 +29,30 @@ namespace IW4MAdmin.Application
Manager.GetLogger().WriteDebug($"Got new event of type {gameEvent.Type} for {gameEvent.Owner}"); Manager.GetLogger().WriteDebug($"Got new event of type {gameEvent.Type} for {gameEvent.Owner}");
#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.Kill ||
gameEvent.Type == GameEvent.EventType.Kill || gameEvent.Type == GameEvent.EventType.Damage ||
gameEvent.Type == GameEvent.EventType.ScriptDamage ||
gameEvent.Type == GameEvent.EventType.ScriptKill ||
gameEvent.Type == GameEvent.EventType.MapChange) 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");
#endif #endif
lock (StatusSensitiveQueue)
{
StatusSensitiveQueue.Enqueue(gameEvent); StatusSensitiveQueue.Enqueue(gameEvent);
}
return; return;
} }
else else
{ {
EventQueue.Enqueue(gameEvent); EventQueue.Enqueue(gameEvent);
Manager.SetHasEvent();
} }
#if DEBUG #if DEBUG
Manager.GetLogger().WriteDebug($"There are now {EventQueue.Count} events in queue"); Manager.GetLogger().WriteDebug($"There are now {EventQueue.Count} events in queue");
#endif #endif
Manager.SetHasEvent();
} }
public string[] GetEventOutput() public string[] GetEventOutput()
@ -55,6 +63,8 @@ namespace IW4MAdmin.Application
public GameEvent GetNextSensitiveEvent() public GameEvent GetNextSensitiveEvent()
{ {
if (StatusSensitiveQueue.Count > 0) if (StatusSensitiveQueue.Count > 0)
{
lock (StatusSensitiveQueue)
{ {
if (!StatusSensitiveQueue.TryDequeue(out GameEvent newEvent)) if (!StatusSensitiveQueue.TryDequeue(out GameEvent newEvent))
{ {
@ -66,6 +76,7 @@ namespace IW4MAdmin.Application
return newEvent; return newEvent;
} }
} }
}
return null; return null;
} }

View File

@ -1,10 +1,7 @@
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IW4MAdmin.Application.IO namespace IW4MAdmin.Application.IO
@ -14,7 +11,6 @@ namespace IW4MAdmin.Application.IO
Server Server; Server Server;
long PreviousFileSize; long PreviousFileSize;
GameLogReader Reader; GameLogReader Reader;
Timer RefreshInfoTimer;
string GameLogFile; string GameLogFile;
class EventState class EventState
@ -28,11 +24,19 @@ namespace IW4MAdmin.Application.IO
GameLogFile = gameLogPath; GameLogFile = gameLogPath;
Reader = new GameLogReader(gameLogPath, server.EventParser); Reader = new GameLogReader(gameLogPath, server.EventParser);
Server = server; Server = server;
RefreshInfoTimer = new Timer(OnEvent, new EventState()
Task.Run(async () =>
{
while (!server.Manager.ShutdownRequested())
{
OnEvent(new EventState()
{ {
Log = server.Manager.GetLogger(), Log = server.Manager.GetLogger(),
ServerId = server.ToString() ServerId = server.ToString()
}, 0, 100); });
await Task.Delay(100);
}
});
} }
private void OnEvent(object state) private void OnEvent(object state)

View File

@ -32,7 +32,7 @@ namespace IW4MAdmin.Application.IO
string newLine; string newLine;
while (!String.IsNullOrEmpty(newLine = rd.ReadLine())) while (!String.IsNullOrEmpty(newLine = rd.ReadLine()))
{ {
logLines.Add(newLine.Replace("\r\n", "")); logLines.Add(newLine);
} }
} }
@ -49,7 +49,7 @@ namespace IW4MAdmin.Application.IO
events.Add(Parser.GetEvent(server, eventLine)); events.Add(Parser.GetEvent(server, eventLine));
} }
catch (Exception e) catch (Exception)
{ {
} }
} }

View File

@ -18,6 +18,7 @@ namespace IW4MAdmin.Application
static public double Version { get; private set; } static public double Version { get; private set; }
static public ApplicationManager ServerManager = ApplicationManager.GetInstance(); static public ApplicationManager ServerManager = ApplicationManager.GetInstance();
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
private static ManualResetEventSlim OnShutdownComplete = new ManualResetEventSlim();
public static void Main(string[] args) public static void Main(string[] args)
{ {
@ -43,6 +44,7 @@ namespace IW4MAdmin.Application
CheckDirectories(); CheckDirectories();
ServerManager = ApplicationManager.GetInstance(); ServerManager = ApplicationManager.GetInstance();
Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey);
Localization.Configure.Initialize(ServerManager.GetApplicationSettings().Configuration()?.CustomLocale); Localization.Configure.Initialize(ServerManager.GetApplicationSettings().Configuration()?.CustomLocale);
loc = Utilities.CurrentLocalization.LocalizationIndex; loc = Utilities.CurrentLocalization.LocalizationIndex;
@ -126,30 +128,21 @@ namespace IW4MAdmin.Application
if (userInput?.Length > 0) if (userInput?.Length > 0)
{ {
Origin.CurrentServer = ServerManager.Servers[0]; Origin.CurrentServer = ServerManager.Servers[0];
GameEvent E = new GameEvent(GameEvent.EventType.Say, userInput, Origin, null, ServerManager.Servers[0]); GameEvent E = new GameEvent()
{
Type = GameEvent.EventType.Command,
Data = userInput,
Origin = Origin,
Owner = ServerManager.Servers[0]
};
ServerManager.GetEventHandler().AddEvent(E); ServerManager.GetEventHandler().AddEvent(E);
E.OnProcessed.Wait();
} }
Console.Write('>'); Console.Write('>');
} while (ServerManager.Running); } while (ServerManager.Running);
}); });
if (ServerManager.GetApplicationSettings().Configuration().EnableWebFront)
{
Task.Run(() =>
{
try
{
WebfrontCore.Program.Init(ServerManager);
}
catch (Exception e)
{
ServerManager.Logger.WriteWarning("Webfront had unhandled exception");
ServerManager.Logger.WriteDebug(e.Message);
}
});
}
} }
catch (Exception e) catch (Exception e)
@ -164,9 +157,21 @@ namespace IW4MAdmin.Application
Console.ReadKey(); Console.ReadKey();
} }
if (ServerManager.GetApplicationSettings().Configuration().EnableWebFront)
{
Task.Run(() => WebfrontCore.Program.Init(ServerManager));
}
OnShutdownComplete.Reset();
ServerManager.Start().Wait(); ServerManager.Start().Wait();
ServerManager.Logger.WriteVerbose(loc["MANAGER_SHUTDOWN_SUCCESS"]); ServerManager.Logger.WriteVerbose(loc["MANAGER_SHUTDOWN_SUCCESS"]);
OnShutdownComplete.Set();
}
private static void OnCancelKey(object sender, ConsoleCancelEventArgs e)
{
ServerManager.Stop();
OnShutdownComplete.Wait();
} }
static void CheckDirectories() static void CheckDirectories()

View File

@ -60,17 +60,10 @@ namespace IW4MAdmin.Application
Api = new EventApi(); Api = new EventApi();
ServerEventOccurred += Api.OnServerEvent; ServerEventOccurred += Api.OnServerEvent;
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings"); ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
Console.CancelKeyPress += new ConsoleCancelEventHandler(OnCancelKey);
StartTime = DateTime.UtcNow; StartTime = DateTime.UtcNow;
OnEvent = new ManualResetEventSlim(); OnEvent = new ManualResetEventSlim();
} }
private void OnCancelKey(object sender, ConsoleCancelEventArgs args)
{
Stop();
}
public IList<Server> GetServers() public IList<Server> GetServers()
{ {
return Servers; return Servers;
@ -141,9 +134,9 @@ namespace IW4MAdmin.Application
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {sensitiveEvent.Owner}"); Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {sensitiveEvent.Owner}");
Logger.WriteDebug("Error Message: " + E.Message); Logger.WriteDebug("Error Message: " + E.Message);
Logger.WriteDebug("Error Trace: " + E.StackTrace); Logger.WriteDebug("Error Trace: " + E.StackTrace);
sensitiveEvent.OnProcessed.Set();
continue;
} }
sensitiveEvent.OnProcessed.Set();
} }
await Task.Delay(5000); await Task.Delay(5000);
@ -152,8 +145,8 @@ namespace IW4MAdmin.Application
public async Task Init() public async Task Init()
{ {
// setup the event handler after the class is initialized Running = true;
Handler = new GameEventHandler(this);
#region DATABASE #region DATABASE
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted)) var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
.Select(c => new .Select(c => new
@ -304,6 +297,8 @@ namespace IW4MAdmin.Application
#region INIT #region INIT
async Task Init(ServerConfiguration Conf) async Task Init(ServerConfiguration Conf)
{ {
// setup the event handler after the class is initialized
Handler = new GameEventHandler(this);
try try
{ {
var ServerInstance = new IW4MServer(this, Conf); var ServerInstance = new IW4MServer(this, Conf);
@ -336,8 +331,6 @@ namespace IW4MAdmin.Application
await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray()); await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray());
#endregion #endregion
Running = true;
} }
private void SendHeartbeat(object state) private void SendHeartbeat(object state)
@ -419,6 +412,12 @@ namespace IW4MAdmin.Application
#endif #endif
} }
// this happens if a plugin requires login
catch (AuthorizationException e)
{
await newEvent.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMAND_NOTAUTHORIZED"]} - {e.Message}");
}
catch (NetworkException e) catch (NetworkException e)
{ {
Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"]); Logger.WriteError(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"]);
@ -449,9 +448,7 @@ namespace IW4MAdmin.Application
} }
// this should allow parallel processing of events // this should allow parallel processing of events
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed await Task.WhenAll(eventList);
Task.WhenAll(eventList);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
// signal that all events have been processed // signal that all events have been processed
OnEvent.Reset(); OnEvent.Reset();
@ -459,8 +456,8 @@ namespace IW4MAdmin.Application
#if !DEBUG #if !DEBUG
HeartbeatTimer.Change(0, Timeout.Infinite); HeartbeatTimer.Change(0, Timeout.Infinite);
foreach (var S in Servers) foreach (var S in _servers)
S.Broadcast("^1" + Utilities.CurrentLocalization.LocalizationIndex["BROADCAST_OFFLINE"]).Wait(); await S.Broadcast("^1" + Utilities.CurrentLocalization.LocalizationIndex["BROADCAST_OFFLINE"]);
#endif #endif
_servers.Clear(); _servers.Clear();
} }

View File

@ -23,11 +23,12 @@ namespace Application.RconParsers
TempBan = "tempbanclient {0} \"{1}\"" TempBan = "tempbanclient {0} \"{1}\""
}; };
private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}) +(-*[0-9]+) +([0-9]+) *$"; private static string StatusRegex = @"^( *[0-9]+) +-*([0-9]+) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){16}|bot[0-9]+|(?:[0-9]+)) +(.{0,20}) +([0-9]+) +(\d+\.\d+\.\d+.\d+\:-*\d{1,5}|0+.0+:-*\d{1,5}) +(-*[0-9]+) +([0-9]+) *$";
public async Task<string[]> ExecuteCommandAsync(Connection connection, string command) public async Task<string[]> ExecuteCommandAsync(Connection connection, string command)
{ {
return (await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command)).Skip(1).ToArray(); var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
return response.Skip(1).ToArray();
} }
public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName) public async Task<Dvar<T>> GetDvarAsync<T>(Connection connection, string dvarName)

View File

@ -25,11 +25,9 @@ namespace IW4MAdmin
{ {
public class IW4MServer : Server public class IW4MServer : Server
{ {
private CancellationToken cts;
private static Index loc = Utilities.CurrentLocalization.LocalizationIndex; private static Index loc = Utilities.CurrentLocalization.LocalizationIndex;
private GameLogEvent LogEvent; private GameLogEvent LogEvent;
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg) { } public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg) { }
public override int GetHashCode() public override int GetHashCode()
@ -196,17 +194,22 @@ namespace IW4MAdmin
Logger.WriteInfo($"Client {player} connecting..."); Logger.WriteInfo($"Client {player} connecting...");
var e = new GameEvent(GameEvent.EventType.Connect, "", player, null, this);
Manager.GetEventHandler().AddEvent(e);
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))
{ {
await player.Kick(Utilities.CurrentLocalization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], new Player() { ClientId = 1 }); await player.Kick(Utilities.CurrentLocalization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], new Player() { ClientId = 1 });
return true;
} }
var e = new GameEvent()
{
Type = GameEvent.EventType.Connect,
Origin = player,
Owner = this
};
Manager.GetEventHandler().AddEvent(e);
return true; return true;
} }
@ -375,14 +378,31 @@ namespace IW4MAdmin
await ProcessEvent(E); await ProcessEvent(E);
Manager.GetEventApi().OnServerEvent(this, E); Manager.GetEventApi().OnServerEvent(this, E);
Command C = null;
if (E.Type == GameEvent.EventType.Command)
{
try
{
C = await ValidateCommand(E);
}
catch (CommandException e)
{
Logger.WriteInfo(e.Message);
}
if (C != null)
{
E.Extra = C;
}
}
// this allows us to catch exceptions but still run it parallel // this allows us to catch exceptions but still run it parallel
async Task pluginHandlingAsync(Task onEvent, string pluginName) async Task pluginHandlingAsync(Task onEvent, string pluginName)
{ {
try try
{ {
if (cts.IsCancellationRequested)
return;
await onEvent; await onEvent;
} }
@ -467,44 +487,7 @@ namespace IW4MAdmin
}); });
} }
else if (E.Type == GameEvent.EventType.Script)
{
Manager.GetEventHandler().AddEvent(GameEvent.TransferWaiter(GameEvent.EventType.Kill, E));
}
if (E.Type == GameEvent.EventType.Say && E.Data?.Length >= 2) if (E.Type == GameEvent.EventType.Say && E.Data?.Length >= 2)
{
if (E.Data.Substring(0, 1) == "!" ||
E.Data.Substring(0, 1) == "@" ||
E.Origin.Level == Player.Permission.Console)
{
Command C = null;
try
{
C = await ValidateCommand(E);
}
catch (CommandException e)
{
Logger.WriteInfo(e.Message);
}
if (C != null)
{
if (C.RequiresTarget && E.Target == null)
{
Logger.WriteWarning("Requested event (command) requiring target does not have a target!");
}
E.Extra = C;
// reprocess event as a command
Manager.GetEventHandler().AddEvent(GameEvent.TransferWaiter(GameEvent.EventType.Command, E));
}
}
else // Not a command
{ {
E.Data = E.Data.StripColors(); E.Data = E.Data.StripColors();
@ -515,7 +498,6 @@ namespace IW4MAdmin
Time = DateTime.UtcNow Time = DateTime.UtcNow
}); });
} }
}
if (E.Type == GameEvent.EventType.MapChange) if (E.Type == GameEvent.EventType.MapChange)
{ {
@ -533,7 +515,6 @@ namespace IW4MAdmin
else else
{ {
Gametype = dict["gametype"].StripColors(); Gametype = dict["gametype"].StripColors();
Hostname = dict["hostname"]?.StripColors(); Hostname = dict["hostname"]?.StripColors();
@ -549,7 +530,11 @@ namespace IW4MAdmin
Hostname = dict["sv_hostname"].StripColors(); Hostname = dict["sv_hostname"].StripColors();
string mapname = dict["mapname"].StripColors(); string mapname = dict["mapname"].StripColors();
CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map() { Alias = mapname, Name = mapname }; CurrentMap = Maps.Find(m => m.Name == mapname) ?? new Map()
{
Alias = mapname,
Name = mapname
};
} }
} }
@ -569,7 +554,6 @@ namespace IW4MAdmin
await E.Owner.ExecuteCommandAsync(E.Message); await E.Owner.ExecuteCommandAsync(E.Message);
} }
//todo: move
while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2)) while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2))
ChatHistory.RemoveAt(0); ChatHistory.RemoveAt(0);
@ -634,18 +618,15 @@ namespace IW4MAdmin
override public async Task<bool> ProcessUpdatesAsync(CancellationToken cts) override public async Task<bool> ProcessUpdatesAsync(CancellationToken cts)
{ {
// this isn't really used anymore
this.cts = cts;
try try
{ {
if (Manager.ShutdownRequested()) if (Manager.ShutdownRequested())
{ {
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
await plugin.OnUnloadAsync();
for (int i = 0; i < Players.Count; i++) for (int i = 0; i < Players.Count; i++)
await RemovePlayer(i); await RemovePlayer(i);
foreach (var plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
await plugin.OnUnloadAsync();
} }
// only check every 2 minutes if the server doesn't seem to be responding // only check every 2 minutes if the server doesn't seem to be responding
@ -746,7 +727,6 @@ namespace IW4MAdmin
if (ServerConfig.UseIW5MParser) if (ServerConfig.UseIW5MParser)
RconParser = new IW5MRConParser(); RconParser = new IW5MRConParser();
var version = await this.GetDvarAsync<string>("version"); var version = await this.GetDvarAsync<string>("version");
GameName = Utilities.GetGame(version.Value); GameName = Utilities.GetGame(version.Value);
@ -838,7 +818,6 @@ namespace IW4MAdmin
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}"; $"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{game.Replace('/', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{logfile.Value}";
} }
// hopefully fix wine drive name mangling // hopefully fix wine drive name mangling
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{ {

View File

@ -13,12 +13,13 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
class Detection class Detection
{ {
int Kills; int Kills;
int HitCount;
int AboveThresholdCount; int AboveThresholdCount;
double AverageKillTime; double AverageKillTime;
Dictionary<IW4Info.HitLocation, int> HitLocationCount; Dictionary<IW4Info.HitLocation, int> HitLocationCount;
double AngleDifferenceAverage; double AngleDifferenceAverage;
EFClientStatistics ClientStats; EFClientStatistics ClientStats;
DateTime LastKill; DateTime LastHit;
long LastOffset; long LastOffset;
ILogger Log; ILogger Log;
Strain Strain; Strain Strain;
@ -74,22 +75,21 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
ClientPenalty = Penalty.PenaltyType.Any, ClientPenalty = Penalty.PenaltyType.Any,
}; };
if (LastKill == DateTime.MinValue) if (LastHit == DateTime.MinValue)
LastKill = DateTime.UtcNow; LastHit = DateTime.UtcNow;
HitLocationCount[kill.HitLoc]++; HitLocationCount[kill.HitLoc]++;
if (!isDamage) if (!isDamage)
{ {
Kills++; Kills++;
AverageKillTime = (AverageKillTime + (DateTime.UtcNow - LastKill).TotalSeconds) / Kills;
} }
HitCount++;
#region VIEWANGLES #region VIEWANGLES
if (kill.AnglesList.Count >= 2) if (kill.AnglesList.Count >= 2)
{ {
double realAgainstPredict = Math.Abs(Vector3.AbsoluteDistance(kill.AnglesList[0], kill.AnglesList[1]) - double realAgainstPredict = Vector3.ViewAngleDistance(kill.AnglesList[0], kill.AnglesList[1], kill.ViewAngles);
(Vector3.AbsoluteDistance(kill.AnglesList[0], kill.ViewAngles) +
Vector3.AbsoluteDistance(kill.AnglesList[1], kill.ViewAngles)));
// LIFETIME // LIFETIME
var hitLoc = ClientStats.HitLocations var hitLoc = ClientStats.HitLocations
@ -102,26 +102,37 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset) if (hitLoc.HitOffsetAverage > Thresholds.MaxOffset)
{ {
Log.WriteDebug("*** Reached Max Lifetime Average for Angle Difference ***");
Log.WriteDebug($"Lifetime Average = {newAverage}");
Log.WriteDebug($"Bone = {hitLoc.Location}");
Log.WriteDebug($"HitCount = {hitLoc.HitCount}");
Log.WriteDebug($"ID = {kill.AttackerId}");
return new DetectionPenaltyResult() return new DetectionPenaltyResult()
{ {
ClientPenalty = Penalty.PenaltyType.Ban, ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = hitLoc.HitOffsetAverage, RatioAmount = hitLoc.HitOffsetAverage,
KillCount = ClientStats.SessionKills, KillCount = hitLoc.HitCount,
}; };
} }
// SESSION // SESSION
int sessHitLocCount = HitLocationCount[kill.HitLoc]; double sessAverage = (AngleDifferenceAverage * (HitCount - 1) + realAgainstPredict) / HitCount;
double sessAverage = (AngleDifferenceAverage * (sessHitLocCount - 1)) + realAgainstPredict / sessHitLocCount;
AngleDifferenceAverage = sessAverage; AngleDifferenceAverage = sessAverage;
if (sessAverage > Thresholds.MaxOffset) if (sessAverage > Thresholds.MaxOffset)
{ {
Log.WriteDebug("*** Reached Max Session Average for Angle Difference ***");
Log.WriteDebug($"Session Average = {sessAverage}");
// Log.WriteDebug($"Bone = {hitLoc.Location}");
Log.WriteDebug($"HitCount = {HitCount}");
Log.WriteDebug($"ID = {kill.AttackerId}");
return new DetectionPenaltyResult() return new DetectionPenaltyResult()
{ {
ClientPenalty = Penalty.PenaltyType.Ban, ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = sessHitLocCount, RatioAmount = sessAverage,
KillCount = ClientStats.SessionKills, KillCount = HitCount,
}; };
} }
@ -130,7 +141,9 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
#endif #endif
} }
var currentStrain = Strain.GetStrain(kill.ViewAngles, kill.TimeOffset - LastOffset); double diff = Math.Max(50, kill.TimeOffset - LastOffset);
var currentStrain = Strain.GetStrain(kill.ViewAngles, diff);
//LastHit = kill.When;
LastOffset = kill.TimeOffset; LastOffset = kill.TimeOffset;
if (currentStrain > ClientStats.MaxStrain) if (currentStrain > ClientStats.MaxStrain)
@ -138,29 +151,38 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
ClientStats.MaxStrain = currentStrain; ClientStats.MaxStrain = currentStrain;
} }
if (currentStrain > Thresholds.MaxStrain)
{
Log.WriteDebug("*** Reached Max Strain ***");
Log.WriteDebug($"Strain = {currentStrain}");
Log.WriteDebug($"Angles = {kill.ViewAngles} {kill.AnglesList[0]} {kill.AnglesList[1]}");
Log.WriteDebug($"Time = {diff}");
Log.WriteDebug($"HitCount = {HitCount}");
Log.WriteDebug($"ID = {kill.AttackerId}");
}
if (Strain.TimesReachedMaxStrain >= 3) if (Strain.TimesReachedMaxStrain >= 3)
{ {
return new DetectionPenaltyResult() return new DetectionPenaltyResult()
{ {
ClientPenalty = Penalty.PenaltyType.Ban, ClientPenalty = Penalty.PenaltyType.Flag,
RatioAmount = ClientStats.MaxStrain, RatioAmount = ClientStats.MaxStrain,
KillCount = ClientStats.SessionKills, KillCount = HitCount,
}; };
} }
#if DEBUG #if DEBUG
Log.WriteDebug($"Current Strain: {currentStrain}"); Log.WriteDebug($"Current Strain: {currentStrain}");
#endif #endif
LastKill = kill.When;
#endregion #endregion
#region SESSION_RATIOS #region SESSION_RATIOS
if (Kills >= Thresholds.LowSampleMinKills) if (Kills >= Thresholds.LowSampleMinKills)
{ {
double marginOfError = Thresholds.GetMarginOfError(Kills); double marginOfError = Thresholds.GetMarginOfError(HitCount);
// determine what the max headshot percentage can be for current number of 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*/ 60 - Thresholds.LowSampleMinKills)); double lerpAmount = Math.Min(1.0, (HitCount - Thresholds.LowSampleMinKills) / (double)(/*Thresholds.HighSampleMinKills*/ 60 - Thresholds.LowSampleMinKills));
double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError; double maxHeadshotLerpValueForFlag = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(2.0), Thresholds.HeadshotRatioThresholdHighSample(2.0), lerpAmount) + marginOfError;
double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError; double maxHeadshotLerpValueForBan = Thresholds.Lerp(Thresholds.HeadshotRatioThresholdLowSample(3.0), Thresholds.HeadshotRatioThresholdHighSample(3.0), lerpAmount) + marginOfError;
// determine what the max bone percentage can be for current number of kills // determine what the max bone percentage can be for current number of kills
@ -168,10 +190,10 @@ namespace IW4MAdmin.Plugins.Stats.Cheat
double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError; double maxBoneRatioLerpValueForBan = Thresholds.Lerp(Thresholds.BoneRatioThresholdLowSample(3.25), Thresholds.BoneRatioThresholdHighSample(3.25), lerpAmount) + marginOfError;
// calculate headshot ratio // calculate headshot ratio
double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet] + HitLocationCount[IW4Info.HitLocation.neck]) / (double)Kills); double currentHeadshotRatio = ((HitLocationCount[IW4Info.HitLocation.head] + HitLocationCount[IW4Info.HitLocation.helmet] + HitLocationCount[IW4Info.HitLocation.neck]) / (double)HitCount);
// calculate maximum bone // calculate maximum bone
double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)Kills).Max()); double currentMaxBoneRatio = (HitLocationCount.Values.Select(v => v / (double)HitCount).Max());
var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key; var bone = HitLocationCount.FirstOrDefault(b => b.Value == HitLocationCount.Values.Max()).Key;
#region HEADSHOT_RATIO #region HEADSHOT_RATIO

View File

@ -132,7 +132,6 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
else else
{ {
// todo: look at this more
statsSvc.ClientStatSvc.Update(clientStats); statsSvc.ClientStatSvc.Update(clientStats);
} }
@ -201,10 +200,9 @@ 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?
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
@ -225,7 +223,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
/// Process stats for kill event /// Process stats for kill event
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task AddScriptKill(bool isDamage, DateTime time, Player attacker, Player victim, int serverId, string map, string hitLoc, string type, public async Task AddScriptHit(bool isDamage, DateTime time, Player attacker, Player victim, int serverId, string map, string hitLoc, string type,
string damage, string weapon, string killOrigin, string deathOrigin, string viewAngles, string offset, string isKillstreakKill, string Ads, string snapAngles) 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];
@ -312,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();
} }
@ -500,7 +498,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
{ {
scoreDifference = clientStats.RoundScore + clientStats.LastScore; scoreDifference = clientStats.RoundScore + clientStats.LastScore;
} }
else else if (clientStats.RoundScore > 0 && clientStats.LastScore < clientStats.RoundScore)
{ {
scoreDifference = clientStats.RoundScore - clientStats.LastScore; scoreDifference = clientStats.RoundScore - clientStats.LastScore;
} }

View File

@ -44,7 +44,8 @@ namespace IW4MAdmin.Plugins.Stats
await Manager.RemovePlayer(E.Origin); await Manager.RemovePlayer(E.Origin);
break; break;
case GameEvent.EventType.Say: case GameEvent.EventType.Say:
if (E.Data != string.Empty && E.Data.Trim().Length > 0 && E.Message.Trim()[0] != '!' && E.Origin.ClientId > 1) if (!string.IsNullOrEmpty(E.Data) &&
E.Origin.ClientId > 1)
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 GameEvent.EventType.MapChange: case GameEvent.EventType.MapChange:
@ -69,23 +70,26 @@ namespace IW4MAdmin.Plugins.Stats
break; break;
case GameEvent.EventType.Flag: case GameEvent.EventType.Flag:
break; break;
case GameEvent.EventType.Script: case GameEvent.EventType.ScriptKill:
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 13)
await Manager.AddScriptHit(false, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13]);
break; break;
case GameEvent.EventType.Kill: case GameEvent.EventType.Kill:
string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; if (!E.Owner.CustomCallback)
if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback)
await Manager.AddScriptKill(false, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13]);
else if (!E.Owner.CustomCallback)
await Manager.AddStandardKill(E.Origin, E.Target); await Manager.AddStandardKill(E.Origin, E.Target);
break; break;
case GameEvent.EventType.Death: case GameEvent.EventType.Death:
break; break;
//case GameEvent.EventType.Damage: case GameEvent.EventType.Damage:
if (!E.Owner.CustomCallback)
Manager.AddDamageEvent(E.Data, E.Origin.ClientId, E.Owner.GetHashCode());
break;
case GameEvent.EventType.ScriptDamage: case GameEvent.EventType.ScriptDamage:
killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0];
if (killInfo.Length >= 9 && E.Owner.CustomCallback) if (killInfo.Length >= 13)
await Manager.AddScriptKill(true, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8], await Manager.AddScriptHit(true, E.Time, E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8],
killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13]); killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12], killInfo[13]);
break; break;
} }

View File

@ -689,7 +689,6 @@ namespace SharedLibraryCore.Commands
public override async Task ExecuteAsync(GameEvent E) public override async Task ExecuteAsync(GameEvent E)
{ {
// todo: move unflag to seperate command
if (E.Target.Level >= E.Origin.Level) if (E.Target.Level >= E.Origin.Level)
{ {
await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FLAG_FAIL"]} ^5{E.Target.Name}"); await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FLAG_FAIL"]} ^5{E.Target.Name}");

View File

@ -33,8 +33,8 @@ namespace SharedLibraryCore
Command, Command,
// FROM GAME // FROM GAME
Script,
ScriptDamage, ScriptDamage,
ScriptKill,
Kill, Kill,
Damage, Damage,
Death, Death,
@ -49,35 +49,19 @@ namespace SharedLibraryCore
Owner = S; Owner = S;
OnProcessed = new ManualResetEventSlim(); OnProcessed = new ManualResetEventSlim();
Time = DateTime.UtcNow; Time = DateTime.UtcNow;
CurrentEventId++;
Id = CurrentEventId;
} }
public GameEvent() public GameEvent()
{ {
OnProcessed = new ManualResetEventSlim(); OnProcessed = new ManualResetEventSlim();
Time = DateTime.UtcNow; Time = DateTime.UtcNow;
CurrentEventId++;
Id = CurrentEventId;
} }
public static GameEvent TransferWaiter(EventType newType, GameEvent e) private static long CurrentEventId;
{
var newEvent = new GameEvent()
{
Data = e.Data,
Extra = e.Extra,
Message = e.Message,
OnProcessed = e.OnProcessed,
Origin = e.Origin,
Owner = e.Owner,
Remote = e.Remote,
Target = e.Target,
Type = newType,
};
// hack: prevent the previous event from completing until this one is done
e.OnProcessed = new ManualResetEventSlim();
newEvent.Time = e.Time;
return newEvent;
}
public EventType Type; public EventType Type;
public string Data; // Data is usually the message sent by player public string Data; // Data is usually the message sent by player
@ -89,5 +73,6 @@ namespace SharedLibraryCore
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; } public DateTime Time { get; private set; }
public long Id { get; private set; }
} }
} }

View File

@ -48,16 +48,41 @@ namespace SharedLibraryCore.Helpers
{ {
double deltaX = Math.Abs(b.X -a.X); double deltaX = Math.Abs(b.X -a.X);
double deltaY = Math.Abs(b.Y - a.Y); double deltaY = Math.Abs(b.Y - a.Y);
// double deltaZ = Math.Abs(b.Z - a.Z); double deltaZ = Math.Abs(b.Z - a.Z);
// this 'fixes' the roll-over angles // this 'fixes' the roll-over angles
double dx = deltaX < 360.0 / 2 ? deltaX : 360.0 - deltaX; double dx = deltaX < 360.0 / 2 ? deltaX : 360.0 - deltaX;
double dy = deltaY < 360.0 / 2 ? deltaY : 360.0 - deltaY; double dy = deltaY < 360.0 / 2 ? deltaY : 360.0 - deltaY;
// double dz = deltaZ < 360.0 / 2 ? deltaZ : 360.0 - deltaZ; double dz = deltaZ < 360.0 / 2 ? deltaZ : 360.0 - deltaZ;
return Math.Sqrt((dx * dx) + (dy * dy) /*+ (dz * dz)*/); return Math.Sqrt((dx * dx) + (dy * dy) /*+ (dz * dz)*/);
} }
public static double ViewAngleDistance(Vector3 a, Vector3 b, Vector3 c)
{
double dabX = Math.Abs(a.X - b.X);
dabX = dabX < 360.0 / 2 ? dabX : 360.0 - dabX;
double dabY = Math.Abs(a.Y - b.Y);
dabY = dabY < 360.0 / 2 ? dabY : 360.0 - dabY;
double dacX = Math.Abs(a.X - c.X);
dacX = dacX < 360.0 / 2 ? dacX : 360.0 - dacX;
double dacY = Math.Abs(a.Y - c.Y);
dacY = dacY < 360.0 / 2 ? dacY : 360.0 - dacY;
double dbcX = Math.Abs(b.X - c.X);
dbcX = dbcX < 360.0 / 2 ? dbcX : 360.0 - dbcX;
double dbcY = Math.Abs(b.Y - c.Y);
dbcY = dbcY < 360.0 / 2 ? dbcY : 360.0 - dbcY;
double deltaX = (dabX - dacX - dbcX) / 2.0;
deltaX = deltaX < 360.0 / 2 ? deltaX : 360.0 - deltaX;
double deltaY = (dabY - dacY - dbcY) / 2.0;
deltaY = deltaY < 360.0 / 2 ? deltaY : 360.0 - deltaY;
return Math.Round(Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY)), 4);
}
public static Vector3 Subtract(Vector3 a, Vector3 b) => new Vector3(b.X - a.X, b.Y - a.Y, b.Z - a.Z); public static Vector3 Subtract(Vector3 a, Vector3 b) => new Vector3(b.X - a.X, b.Y - a.Y, b.Z - a.Z);
public double DotProduct(Vector3 a) => (a.X * this.X) + (a.Y * this.Y) + (a.Z * this.Z); public double DotProduct(Vector3 a) => (a.X * this.X) + (a.Y * this.Y) + (a.Z * this.Z);

View File

@ -40,8 +40,14 @@ namespace SharedLibraryCore.Objects
public async Task Tell(String Message) public async Task Tell(String Message)
{ {
// this is console or remote so send immediately
if (ClientNumber < 0)
{
await CurrentServer.Tell(Message, this);
}
// await CurrentServer.Tell(Message, this); else
{
var e = new GameEvent() var e = new GameEvent()
{ {
Message = Message, Message = Message,
@ -52,8 +58,7 @@ namespace SharedLibraryCore.Objects
}; };
CurrentServer.Manager.GetEventHandler().AddEvent(e); CurrentServer.Manager.GetEventHandler().AddEvent(e);
// this ensures the output it sent before returning }
await Task.Run(() => e.OnProcessed.Wait());
} }
public async Task Kick(String Message, Player Sender) public async Task Kick(String Message, Player Sender)

View File

@ -56,8 +56,6 @@ namespace SharedLibraryCore.RCon
{ {
public IPEndPoint Endpoint { get; private set; } public IPEndPoint Endpoint { get; private set; }
public string RConPassword { get; private set; } public string RConPassword { get; private set; }
public ConcurrentQueue<ManualResetEventSlim> ResponseQueue;
//Socket ServerConnection;
ILogger Log; ILogger Log;
int FailedSends; int FailedSends;
int FailedReceives; int FailedReceives;
@ -79,13 +77,6 @@ namespace SharedLibraryCore.RCon
OnReceived = new ManualResetEvent(false); OnReceived = new ManualResetEvent(false);
} }
~Connection()
{
/*ServerConnection.Shutdown(SocketShutdown.Both);
ServerConnection.Close();
ServerConnection.Dispose();*/
}
private void OnConnectedCallback(IAsyncResult ar) private void OnConnectedCallback(IAsyncResult ar)
{ {
var serverSocket = (Socket)ar.AsyncState; var serverSocket = (Socket)ar.AsyncState;
@ -144,12 +135,12 @@ namespace SharedLibraryCore.RCon
if (!connectionState.Buffer.Take(4).ToArray().SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF })) if (!connectionState.Buffer.Take(4).ToArray().SequenceEqual(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF }))
throw new NetworkException("Unexpected packet received"); throw new NetworkException("Unexpected packet received");
if (FailedReceives == 0 && serverConnection.Available > 0) /* if (FailedReceives == 0 && 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*/
{ {
response = connectionState.ResponseString.ToString(); response = connectionState.ResponseString.ToString();
OnReceived.Set(); OnReceived.Set();
@ -169,7 +160,7 @@ namespace SharedLibraryCore.RCon
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
Log.WriteWarning($"Tried to check for more available bytes for disposed socket on {Endpoint}"); // Log.WriteWarning($"Tried to check for more available bytes for disposed socket on {Endpoint}");
} }
} }
@ -211,7 +202,9 @@ namespace SharedLibraryCore.RCon
retrySend: retrySend:
try try
{ {
#if DEBUG
Console.WriteLine($"Sending Command {parameters}");
#endif
if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout)) if (!OnConnected.WaitOne(StaticHelpers.SocketTimeout))
throw new SocketException((int)SocketError.TimedOut); throw new SocketException((int)SocketError.TimedOut);

View File

@ -41,7 +41,6 @@ namespace SharedLibraryCore
PlayerHistory = new Queue<PlayerHistory>(); PlayerHistory = new Queue<PlayerHistory>();
ChatHistory = new List<ChatInfo>(); ChatHistory = new List<ChatInfo>();
NextMessage = 0; NextMessage = 0;
OnEvent = new ManualResetEventSlim();
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName; CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName; CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
InitializeTokens(); InitializeTokens();
@ -139,8 +138,8 @@ namespace SharedLibraryCore
Manager.GetEventHandler().AddEvent(e); Manager.GetEventHandler().AddEvent(e);
#else #else
Logger.WriteVerbose(Message.StripColors()); Logger.WriteVerbose(Message.StripColors());
await Task.CompletedTask;
#endif #endif
await Task.CompletedTask;
} }
/// <summary> /// <summary>
@ -162,19 +161,22 @@ namespace SharedLibraryCore
if (Target.Level == Player.Permission.Console) if (Target.Level == Player.Permission.Console)
{ {
Console.ForegroundColor = ConsoleColor.Cyan; Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(Utilities.StripColors(Message)); Console.WriteLine(Message.StripColors());
Console.ForegroundColor = ConsoleColor.Gray; Console.ForegroundColor = ConsoleColor.Gray;
} }
if (CommandResult.Count > 15) if (CommandResult.Count > 15)
CommandResult.RemoveAt(0); CommandResult.RemoveAt(0);
if (Target.ClientNumber < 0)
{
CommandResult.Add(new CommandResponseInfo() CommandResult.Add(new CommandResponseInfo()
{ {
Response = Utilities.StripColors(Message), Response = Message.StripColors(),
ClientId = Target.ClientId ClientId = Target.ClientId
}); });
} }
}
/// <summary> /// <summary>
/// Send a message to all admins on the server /// Send a message to all admins on the server
@ -315,7 +317,6 @@ namespace SharedLibraryCore
public RCon.Connection RemoteConnection { get; protected set; } public RCon.Connection RemoteConnection { get; protected set; }
public IRConParser RconParser { get; protected set; } public IRConParser RconParser { get; protected set; }
public IEventParser EventParser { get; set; } public IEventParser EventParser { get; set; }
public ManualResetEventSlim OnEvent { get; private set; }
// Internal // Internal
protected string IP; protected string IP;
@ -327,6 +328,7 @@ namespace SharedLibraryCore
protected TimeSpan LastMessage; protected TimeSpan LastMessage;
protected IFile LogFile; protected IFile LogFile;
protected DateTime LastPoll; protected DateTime LastPoll;
protected ManualResetEventSlim OnRemoteCommandResponse;
// only here for performance // only here for performance
private bool CustomSayEnabled; private bool CustomSayEnabled;

View File

@ -407,7 +407,7 @@ namespace SharedLibraryCore
public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) => server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue); public static Task SetDvarAsync(this Server server, string dvarName, object dvarValue) => server.RconParser.SetDvarAsync(server.RemoteConnection, dvarName, dvarValue);
public static Task<string[]> ExecuteCommandAsync(this Server server, string commandName) => server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName); public static async Task<string[]> ExecuteCommandAsync(this Server server, string commandName) => await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
public static Task<List<Player>> GetStatusAsync(this Server server) => server.RconParser.GetStatusAsync(server.RemoteConnection); public static Task<List<Player>> GetStatusAsync(this Server server) => server.RconParser.GetStatusAsync(server.RemoteConnection);

View File

@ -39,7 +39,7 @@ namespace WebfrontCore.Controllers
var remoteEvent = new GameEvent() var remoteEvent = new GameEvent()
{ {
Type = GameEvent.EventType.Say, Type = GameEvent.EventType.Command,
Data = command, Data = command,
Origin = client, Origin = client,
Owner = server, Owner = server,
@ -48,8 +48,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(5000));
await Task.Run(() => remoteEvent.OnProcessed.Wait());
var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList(); var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
// remove the added command response // remove the added command response

View File

@ -45,7 +45,7 @@
<div id="profile_aliases" class="pr-0 pr-sm-4 pb-2 mb-2 text-muted order-0"> <div id="profile_aliases" class="pr-0 pr-sm-4 pb-2 mb-2 text-muted order-0">
@{ @{
@Model.NetworkId.ToString("X") <br/> <span class="text-secondary">@Model.NetworkId.ToString("X")</span> <br />
foreach (string alias in Model.Aliases) foreach (string alias in Model.Aliases)
{ {
@alias <br /> @alias <br />