reworked event management (again)
almost finished
This commit is contained in:
parent
0538d9f479
commit
56cb8c50e7
@ -5,7 +5,7 @@
|
|||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
|
||||||
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Application</PackageId>
|
||||||
<Version>2.1.4</Version>
|
<Version>2.1.5</Version>
|
||||||
<Authors>RaidMax</Authors>
|
<Authors>RaidMax</Authors>
|
||||||
<Company>Forever None</Company>
|
<Company>Forever None</Company>
|
||||||
<Product>IW4MAdmin</Product>
|
<Product>IW4MAdmin</Product>
|
||||||
|
@ -36,7 +36,7 @@ namespace IW4MAdmin.Application.Core
|
|||||||
if (!AuthenticatedClients.TryGetValue(client.NetworkId, out Player value))
|
if (!AuthenticatedClients.TryGetValue(client.NetworkId, out Player value))
|
||||||
{
|
{
|
||||||
// authenticate them
|
// authenticate them
|
||||||
client.IsAuthenticated = true;
|
client.State = Player.ClientState.Authenticated;
|
||||||
AuthenticatedClients.Add(client.NetworkId, client);
|
AuthenticatedClients.Add(client.NetworkId, client);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -57,7 +57,7 @@ namespace IW4MAdmin.Application.Core
|
|||||||
if (!AuthenticatedClients.TryGetValue(clientToAuthenticate.NetworkId, out Player value))
|
if (!AuthenticatedClients.TryGetValue(clientToAuthenticate.NetworkId, out Player value))
|
||||||
{
|
{
|
||||||
// authenticate them
|
// authenticate them
|
||||||
clientToAuthenticate.IsAuthenticated = true;
|
clientToAuthenticate.State = Player.ClientState.Authenticated;
|
||||||
AuthenticatedClients.Add(clientToAuthenticate.NetworkId, clientToAuthenticate);
|
AuthenticatedClients.Add(clientToAuthenticate.NetworkId, clientToAuthenticate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||||
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString())
|
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||||
|
State = Player.ClientState.Connecting
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,101 +11,6 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
class T6MEventParser : IW4EventParser
|
class T6MEventParser : IW4EventParser
|
||||||
{
|
{
|
||||||
/*public GameEvent GetEvent(Server server, string logLine)
|
|
||||||
{
|
|
||||||
string cleanedEventLine = Regex.Replace(logLine, @"^ *[0-9]+:[0-9]+ *", "").Trim();
|
|
||||||
string[] lineSplit = cleanedEventLine.Split(';');
|
|
||||||
|
|
||||||
if (lineSplit[0][0] == 'K')
|
|
||||||
{
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Kill,
|
|
||||||
Data = cleanedEventLine,
|
|
||||||
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
|
|
||||||
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
|
|
||||||
Owner = server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineSplit[0][0] == 'D')
|
|
||||||
{
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Damage,
|
|
||||||
Data = cleanedEventLine,
|
|
||||||
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 6)),
|
|
||||||
Target = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
|
|
||||||
Owner = server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineSplit[0] == "say" || lineSplit[0] == "sayteam")
|
|
||||||
{
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Say,
|
|
||||||
Data = lineSplit[4],
|
|
||||||
Origin = server.GetPlayersAsList().First(c => c.ClientNumber == Utilities.ClientIdFromString(lineSplit, 2)),
|
|
||||||
Owner = server,
|
|
||||||
Message = lineSplit[4]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineSplit[0].Contains("ExitLevel"))
|
|
||||||
{
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.MapEnd,
|
|
||||||
Data = lineSplit[0],
|
|
||||||
Origin = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Target = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Owner = server
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineSplit[0].Contains("InitGame"))
|
|
||||||
{
|
|
||||||
string dump = cleanedEventLine.Replace("InitGame: ", "");
|
|
||||||
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.MapChange,
|
|
||||||
Data = lineSplit[0],
|
|
||||||
Origin = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Target = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Owner = server,
|
|
||||||
Extra = dump.DictionaryFromKeyValue()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Unknown,
|
|
||||||
Origin = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Target = new Player()
|
|
||||||
{
|
|
||||||
ClientId = 1
|
|
||||||
},
|
|
||||||
Owner = server
|
|
||||||
};
|
|
||||||
}*/
|
|
||||||
|
|
||||||
public override string GetGameDir() => $"t6r{Path.DirectorySeparatorChar}data";
|
public override string GetGameDir() => $"t6r{Path.DirectorySeparatorChar}data";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,61 +8,20 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
class GameEventHandler : IEventHandler
|
class GameEventHandler : IEventHandler
|
||||||
{
|
{
|
||||||
private ConcurrentQueue<GameEvent> EventQueue;
|
private readonly IManager Manager;
|
||||||
private Queue<GameEvent> DelayedEventQueue;
|
|
||||||
private IManager Manager;
|
|
||||||
|
|
||||||
public GameEventHandler(IManager mgr)
|
public GameEventHandler(IManager mgr)
|
||||||
{
|
{
|
||||||
EventQueue = new ConcurrentQueue<GameEvent>();
|
|
||||||
DelayedEventQueue = new Queue<GameEvent>();
|
|
||||||
|
|
||||||
Manager = mgr;
|
Manager = mgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEvent(GameEvent gameEvent, bool delayedExecution = false)
|
public void AddEvent(GameEvent gameEvent)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
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
|
||||||
if (delayedExecution)
|
// todo: later
|
||||||
{
|
((Manager as ApplicationManager).OnServerEvent)(this, new ApplicationManager.GameEventArgs(null, false, gameEvent));
|
||||||
DelayedEventQueue.Enqueue(gameEvent);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EventQueue.Enqueue(gameEvent);
|
|
||||||
Manager.SetHasEvent();
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
Manager.GetLogger().WriteDebug($"There are now {EventQueue.Count} events in queue");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] GetEventOutput()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameEvent GetNextEvent()
|
|
||||||
{
|
|
||||||
if (EventQueue.Count > 0)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
Manager.GetLogger().WriteDebug("Getting next event to be processed");
|
|
||||||
#endif
|
|
||||||
if (!EventQueue.TryDequeue(out GameEvent newEvent))
|
|
||||||
{
|
|
||||||
Manager.GetLogger().WriteError("Could not dequeue event for processing");
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return newEvent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,7 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
OnShutdownComplete.Reset();
|
OnShutdownComplete.Reset();
|
||||||
ServerManager.Start().Wait();
|
ServerManager.Start();
|
||||||
ServerManager.Logger.WriteVerbose(loc["MANAGER_SHUTDOWN_SUCCESS"]);
|
ServerManager.Logger.WriteVerbose(loc["MANAGER_SHUTDOWN_SUCCESS"]);
|
||||||
OnShutdownComplete.Set();
|
OnShutdownComplete.Set();
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,11 @@ namespace IW4MAdmin.Application
|
|||||||
public ILogger Logger { get; private set; }
|
public ILogger Logger { get; private set; }
|
||||||
public bool Running { get; private set; }
|
public bool Running { get; private set; }
|
||||||
public bool IsInitialized { get; private set; }
|
public bool IsInitialized { get; private set; }
|
||||||
public EventHandler<GameEvent> ServerEventOccurred { get; private set; }
|
//public EventHandler<GameEvent> ServerEventOccurred { get; private set; }
|
||||||
|
// define what the delagate function looks like
|
||||||
|
public delegate void OnServerEventEventHandler(object sender, GameEventArgs e);
|
||||||
|
// expose the event handler so we can execute the events
|
||||||
|
public OnServerEventEventHandler OnServerEvent { get; private set; }
|
||||||
public DateTime StartTime { get; private set; }
|
public DateTime StartTime { get; private set; }
|
||||||
|
|
||||||
static ApplicationManager Instance;
|
static ApplicationManager Instance;
|
||||||
@ -48,6 +52,17 @@ namespace IW4MAdmin.Application
|
|||||||
ManualResetEventSlim OnEvent;
|
ManualResetEventSlim OnEvent;
|
||||||
readonly IPageList PageList;
|
readonly IPageList PageList;
|
||||||
|
|
||||||
|
public class GameEventArgs : System.ComponentModel.AsyncCompletedEventArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
public GameEventArgs(Exception error, bool cancelled, GameEvent userState) : base(error, cancelled, userState)
|
||||||
|
{
|
||||||
|
Event = userState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameEvent Event { get; }
|
||||||
|
}
|
||||||
|
|
||||||
private ApplicationManager()
|
private ApplicationManager()
|
||||||
{
|
{
|
||||||
Logger = new Logger($@"{Utilities.OperatingDirectory}IW4MAdmin.log");
|
Logger = new Logger($@"{Utilities.OperatingDirectory}IW4MAdmin.log");
|
||||||
@ -60,11 +75,96 @@ namespace IW4MAdmin.Application
|
|||||||
PenaltySvc = new PenaltyService();
|
PenaltySvc = new PenaltyService();
|
||||||
PrivilegedClients = new Dictionary<int, Player>();
|
PrivilegedClients = new Dictionary<int, Player>();
|
||||||
Api = new EventApi();
|
Api = new EventApi();
|
||||||
ServerEventOccurred += Api.OnServerEvent;
|
//ServerEventOccurred += Api.OnServerEvent;
|
||||||
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
||||||
StartTime = DateTime.UtcNow;
|
StartTime = DateTime.UtcNow;
|
||||||
OnEvent = new ManualResetEventSlim();
|
OnEvent = new ManualResetEventSlim();
|
||||||
PageList = new PageList();
|
PageList = new PageList();
|
||||||
|
OnServerEvent += OnServerEventAsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnServerEventAsync(object sender, GameEventArgs args)
|
||||||
|
{
|
||||||
|
var newEvent = args.Event;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// if the origin client is not in an authorized state (detected by RCon) don't execute the event
|
||||||
|
if (GameEvent.ShouldOriginEventBeDelayed(newEvent))
|
||||||
|
{
|
||||||
|
Logger.WriteDebug($"Delaying origin execution of event type {newEvent.Type} for {newEvent.Origin} because they are not authed");
|
||||||
|
// offload it to the player to keep
|
||||||
|
newEvent.Origin.DelayedEvents.Enqueue(newEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the target client is not in an authorized state (detected by RCon) don't execute the event
|
||||||
|
if (GameEvent.ShouldTargetEventBeDelayed(newEvent))
|
||||||
|
{
|
||||||
|
Logger.WriteDebug($"Delaying target execution of event type {newEvent.Type} for {newEvent.Target} because they are not authed");
|
||||||
|
// offload it to the player to keep
|
||||||
|
newEvent.Target.DelayedEvents.Enqueue(newEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||||
|
|
||||||
|
//// todo: this is a hacky mess
|
||||||
|
if (newEvent.Origin?.DelayedEvents?.Count > 0 &&
|
||||||
|
newEvent.Origin?.State == Player.ClientState.Connected)
|
||||||
|
{
|
||||||
|
var events = newEvent.Origin.DelayedEvents;
|
||||||
|
|
||||||
|
// add the delayed event to the queue
|
||||||
|
while (events?.Count > 0)
|
||||||
|
{
|
||||||
|
var e = events.Dequeue();
|
||||||
|
e.Origin = newEvent.Origin;
|
||||||
|
// check if the target was assigned
|
||||||
|
if (e.Target != null)
|
||||||
|
{
|
||||||
|
// update the target incase they left or have newer info
|
||||||
|
e.Target = newEvent.Owner.GetPlayersAsList()
|
||||||
|
.FirstOrDefault(p => p.NetworkId == e.Target.NetworkId);
|
||||||
|
// we have to throw out the event because they left
|
||||||
|
if (e.Target == null)
|
||||||
|
{
|
||||||
|
Logger.WriteWarning($"Delayed event for {e.Origin} was removed because the target has left");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.GetEventHandler().AddEvent(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
Logger.WriteDebug("Processed Event");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// this happens if a plugin requires login
|
||||||
|
catch (AuthorizationException ex)
|
||||||
|
{
|
||||||
|
await newEvent.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMAND_NOTAUTHORIZED"]} - {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (NetworkException ex)
|
||||||
|
{
|
||||||
|
Logger.WriteError(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (ServerException ex)
|
||||||
|
{
|
||||||
|
Logger.WriteWarning(ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {newEvent.Owner}");
|
||||||
|
Logger.WriteDebug("Error Message: " + ex.Message);
|
||||||
|
Logger.WriteDebug("Error Trace: " + ex.StackTrace);
|
||||||
|
}
|
||||||
|
// tell anyone waiting for the output that we're done
|
||||||
|
newEvent.OnProcessed.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<Server> GetServers()
|
public IList<Server> GetServers()
|
||||||
@ -91,7 +191,9 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
// select the server ids that have completed the update task
|
// select the server ids that have completed the update task
|
||||||
var serverTasksToRemove = runningUpdateTasks
|
var serverTasksToRemove = runningUpdateTasks
|
||||||
.Where(ut => ut.Value.Status != TaskStatus.Running)
|
.Where(ut => ut.Value.Status == TaskStatus.RanToCompletion ||
|
||||||
|
ut.Value.Status == TaskStatus.Canceled ||
|
||||||
|
ut.Value.Status == TaskStatus.Faulted)
|
||||||
.Select(ut => ut.Key)
|
.Select(ut => ut.Key)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -109,7 +211,8 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
// select the servers where the tasks have completed
|
// select the servers where the tasks have completed
|
||||||
foreach (var server in Servers.Where(s => serverTasksToRemove.Count == 0 ? true : serverTasksToRemove.Contains(GetHashCode())))
|
var serverIds = Servers.Select(s => s.GetHashCode()).Except(runningUpdateTasks.Select(r => r.Key)).ToList();
|
||||||
|
foreach (var server in Servers.Where(s => serverIds.Contains(s.GetHashCode())))
|
||||||
{
|
{
|
||||||
runningUpdateTasks.Add(server.GetHashCode(), Task.Run(async () =>
|
runningUpdateTasks.Add(server.GetHashCode(), Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -133,7 +236,7 @@ namespace IW4MAdmin.Application
|
|||||||
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
#endif
|
#endif
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
await Task.Delay(30000);
|
await Task.Delay(10000);
|
||||||
#else
|
#else
|
||||||
await Task.Delay(ConfigHandler.Configuration().RConPollRate);
|
await Task.Delay(ConfigHandler.Configuration().RConPollRate);
|
||||||
#endif
|
#endif
|
||||||
@ -397,7 +500,7 @@ namespace IW4MAdmin.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
// this needs to be run seperately from the main thread
|
// this needs to be run seperately from the main thread
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
@ -408,101 +511,11 @@ namespace IW4MAdmin.Application
|
|||||||
Task.Run(() => UpdateServerStates());
|
Task.Run(() => UpdateServerStates());
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||||
|
|
||||||
var eventList = new List<Task>();
|
|
||||||
|
|
||||||
async Task processEvent(GameEvent newEvent)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
|
||||||
|
|
||||||
// todo: this is a hacky mess
|
|
||||||
if (newEvent.Origin?.DelayedEvents?.Count > 0 &&
|
|
||||||
newEvent.Origin?.State == Player.ClientState.Connected)
|
|
||||||
{
|
|
||||||
var events = newEvent.Origin.DelayedEvents;
|
|
||||||
|
|
||||||
// add the delayed event to the queue
|
|
||||||
while (events?.Count > 0)
|
|
||||||
{
|
|
||||||
var e = events.Dequeue();
|
|
||||||
e.Origin = newEvent.Origin;
|
|
||||||
// check if the target was assigned
|
|
||||||
if (e.Target != null)
|
|
||||||
{
|
|
||||||
// update the target incase they left or have newer info
|
|
||||||
e.Target = newEvent.Owner.GetPlayersAsList()
|
|
||||||
.FirstOrDefault(p => p.NetworkId == e.Target.NetworkId);
|
|
||||||
// we have to throw out the event because they left
|
|
||||||
if (e.Target == null)
|
|
||||||
{
|
|
||||||
Logger.WriteWarning($"Delayed event for {e.Origin} was removed because the target has left");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.GetEventHandler().AddEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
Logger.WriteDebug("Processed Event");
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
Logger.WriteError(e.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
Logger.WriteError($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_EXCEPTION"]} {newEvent.Owner}");
|
|
||||||
Logger.WriteDebug("Error Message: " + E.Message);
|
|
||||||
Logger.WriteDebug("Error Trace: " + E.StackTrace);
|
|
||||||
}
|
|
||||||
// tell anyone waiting for the output that we're done
|
|
||||||
newEvent.OnProcessed.Set();
|
|
||||||
};
|
|
||||||
|
|
||||||
GameEvent queuedEvent = null;
|
|
||||||
|
|
||||||
while (Running)
|
while (Running)
|
||||||
{
|
{
|
||||||
// wait for new event to be added
|
|
||||||
OnEvent.Wait();
|
OnEvent.Wait();
|
||||||
while ((queuedEvent = Handler.GetNextEvent()) != null)
|
|
||||||
{
|
|
||||||
if (GameEvent.ShouldOriginEventBeDelayed(queuedEvent))
|
|
||||||
{
|
|
||||||
Logger.WriteDebug($"Delaying origin execution of event type {queuedEvent.Type} for {queuedEvent.Origin} because they are not authed");
|
|
||||||
// offload it to the player to keep
|
|
||||||
queuedEvent.Origin.DelayedEvents.Enqueue(queuedEvent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GameEvent.ShouldTargetEventBeDelayed(queuedEvent))
|
|
||||||
{
|
|
||||||
Logger.WriteDebug($"Delaying target execution of event type {queuedEvent.Type} for {queuedEvent.Target} because they are not authed");
|
|
||||||
// offload it to the player to keep
|
|
||||||
queuedEvent.Target.DelayedEvents.Enqueue(queuedEvent);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// for delayed events, they're added after the connect event so it should work out
|
|
||||||
await processEvent(queuedEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// signal that all events have been processed
|
|
||||||
OnEvent.Reset();
|
OnEvent.Reset();
|
||||||
}
|
}
|
||||||
#if !DEBUG
|
|
||||||
foreach (var S in _servers)
|
|
||||||
await S.Broadcast("^1" + Utilities.CurrentLocalization.LocalizationIndex["BROADCAST_OFFLINE"]);
|
|
||||||
#endif
|
|
||||||
_servers.Clear();
|
_servers.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,8 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
IPAddress = ip == 0 ? int.MinValue : ip,
|
IPAddress = ip == 0 ? int.MinValue : ip,
|
||||||
Ping = ping,
|
Ping = ping,
|
||||||
Score = score,
|
Score = score,
|
||||||
IsBot = ip == 0
|
IsBot = ip == 0,
|
||||||
|
State = Player.ClientState.Connecting
|
||||||
};
|
};
|
||||||
|
|
||||||
StatusPlayers.Add(P);
|
StatusPlayers.Add(P);
|
||||||
|
@ -153,7 +153,8 @@ namespace IW4MAdmin.WApplication.RconParsers
|
|||||||
IPAddress = ipAddress,
|
IPAddress = ipAddress,
|
||||||
Ping = Ping,
|
Ping = Ping,
|
||||||
Score = score,
|
Score = score,
|
||||||
IsBot = false
|
IsBot = false,
|
||||||
|
State = Player.ClientState.Connecting
|
||||||
};
|
};
|
||||||
|
|
||||||
StatusPlayers.Add(p);
|
StatusPlayers.Add(p);
|
||||||
|
@ -185,6 +185,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
IPAddress = ipAddress,
|
IPAddress = ipAddress,
|
||||||
Ping = Ping,
|
Ping = Ping,
|
||||||
Score = score,
|
Score = score,
|
||||||
|
State = Player.ClientState.Connecting,
|
||||||
IsBot = networkId == 0
|
IsBot = networkId == 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -68,32 +68,21 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
override public async Task<bool> AddPlayer(Player polledPlayer)
|
override public async Task<bool> AddPlayer(Player polledPlayer)
|
||||||
{
|
{
|
||||||
if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
//if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
||||||
polledPlayer.Ping < 1 ||
|
// polledPlayer.Ping < 1 ||
|
||||||
|
if (
|
||||||
polledPlayer.ClientNumber < 0)
|
polledPlayer.ClientNumber < 0)
|
||||||
{
|
{
|
||||||
//Logger.WriteDebug($"Skipping client not in connected state {P}");
|
//Logger.WriteDebug($"Skipping client not in connected state {P}");
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Players[polledPlayer.ClientNumber] != null &&
|
// set this when they are waiting for authentication
|
||||||
Players[polledPlayer.ClientNumber].NetworkId == polledPlayer.NetworkId &&
|
if (Players[polledPlayer.ClientNumber] == null &&
|
||||||
Players[polledPlayer.ClientNumber].State == Player.ClientState.Connected)
|
polledPlayer.State == Player.ClientState.Connecting)
|
||||||
{
|
|
||||||
// update their ping & score
|
|
||||||
Players[polledPlayer.ClientNumber].Ping = polledPlayer.Ping;
|
|
||||||
Players[polledPlayer.ClientNumber].Score = polledPlayer.Score;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Players[polledPlayer.ClientNumber] == null)
|
|
||||||
{
|
{
|
||||||
Players[polledPlayer.ClientNumber] = polledPlayer;
|
Players[polledPlayer.ClientNumber] = polledPlayer;
|
||||||
}
|
return false;
|
||||||
|
|
||||||
if (!polledPlayer.IsAuthenticated)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
@ -196,7 +185,6 @@ namespace IW4MAdmin
|
|||||||
player.ClientNumber = polledPlayer.ClientNumber;
|
player.ClientNumber = polledPlayer.ClientNumber;
|
||||||
player.IsBot = polledPlayer.IsBot;
|
player.IsBot = polledPlayer.IsBot;
|
||||||
player.Score = polledPlayer.Score;
|
player.Score = polledPlayer.Score;
|
||||||
player.IsAuthenticated = true;
|
|
||||||
player.CurrentServer = this;
|
player.CurrentServer = this;
|
||||||
Players[player.ClientNumber] = player;
|
Players[player.ClientNumber] = player;
|
||||||
|
|
||||||
@ -246,18 +234,9 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
// they didn't fully connect so empty their slot
|
// they didn't fully connect so empty their slot
|
||||||
Players[player.ClientNumber] = null;
|
Players[player.ClientNumber] = null;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Connect,
|
|
||||||
Origin = player,
|
|
||||||
Owner = this
|
|
||||||
};
|
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
|
||||||
|
|
||||||
player.State = Player.ClientState.Connected;
|
player.State = Player.ClientState.Connected;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -278,8 +257,10 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
Player Leaving = Players[cNum];
|
Player Leaving = Players[cNum];
|
||||||
Logger.WriteInfo($"Client {Leaving}, state {Leaving.State.ToString()} disconnecting...");
|
Logger.WriteInfo($"Client {Leaving}, state {Leaving.State.ToString()} disconnecting...");
|
||||||
|
Leaving.State = Player.ClientState.Disconnecting;
|
||||||
|
|
||||||
if (!Leaving.IsAuthenticated || Leaving.State != Player.ClientState.Connected)
|
// occurs when the player disconnects via log before being authenticated by RCon
|
||||||
|
if (Leaving.State != Player.ClientState.Connected)
|
||||||
{
|
{
|
||||||
Players[cNum] = null;
|
Players[cNum] = null;
|
||||||
}
|
}
|
||||||
@ -394,8 +375,29 @@ namespace IW4MAdmin
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
override protected async Task ProcessEvent(GameEvent E)
|
override protected async Task ProcessEvent(GameEvent E)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (E.Type == GameEvent.EventType.StatusUpdate)
|
||||||
|
{
|
||||||
|
// this event gets called before they're full connected
|
||||||
|
if (E.Origin != null)
|
||||||
|
{
|
||||||
|
//var existingClient = Players[E.Origin.ClientNumber] ?? E.Origin;
|
||||||
|
//existingClient.Ping = E.Origin.Ping;
|
||||||
|
//existingClient.Score = E.Origin.Score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Connect)
|
if (E.Type == GameEvent.EventType.Connect)
|
||||||
{
|
{
|
||||||
|
E.Origin.State = Player.ClientState.Authenticated;
|
||||||
|
// add them to the server
|
||||||
|
if (!await AddPlayer(E.Origin))
|
||||||
|
{
|
||||||
|
throw new ServerException("Player didn't pass authorization, so we are discontinuing event");
|
||||||
|
}
|
||||||
|
// hack makes the event propgate with the correct info
|
||||||
|
E.Origin = Players[E.Origin.ClientNumber];
|
||||||
|
|
||||||
ChatHistory.Add(new ChatInfo()
|
ChatHistory.Add(new ChatInfo()
|
||||||
{
|
{
|
||||||
Name = E.Origin?.Name ?? "ERROR!",
|
Name = E.Origin?.Name ?? "ERROR!",
|
||||||
@ -427,16 +429,11 @@ namespace IW4MAdmin
|
|||||||
Owner = this
|
Owner = this
|
||||||
};
|
};
|
||||||
|
|
||||||
if (e.Origin != null)
|
|
||||||
{
|
|
||||||
e.Origin.State = Player.ClientState.Disconnecting;
|
|
||||||
}
|
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (origin != null &&
|
else if (origin != null &&
|
||||||
origin.State == Player.ClientState.Connecting)
|
origin.State != Player.ClientState.Connected)
|
||||||
{
|
{
|
||||||
await RemovePlayer(origin.ClientNumber);
|
await RemovePlayer(origin.ClientNumber);
|
||||||
}
|
}
|
||||||
@ -540,61 +537,36 @@ namespace IW4MAdmin
|
|||||||
ChatHistory.Clear();
|
ChatHistory.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<int> PollPlayersAsync()
|
/// <summary>
|
||||||
|
/// lists the connecting and disconnecting clients via RCon response
|
||||||
|
/// array index 0 = connecting clients
|
||||||
|
/// array index 1 = disconnecting clients
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
async Task<IList<Player>[]> PollPlayersAsync()
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
var now = DateTime.Now;
|
var now = DateTime.Now;
|
||||||
|
#endif
|
||||||
List<Player> CurrentPlayers = null;
|
var currentClients = GetPlayersAsList();
|
||||||
try
|
var polledClients = await this.GetStatusAsync();
|
||||||
{
|
|
||||||
CurrentPlayers = await this.GetStatusAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
// when the server has lost connection
|
|
||||||
catch (NetworkException)
|
|
||||||
{
|
|
||||||
Throttled = true;
|
|
||||||
return ClientNum;
|
|
||||||
}
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
|
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
|
||||||
#endif
|
#endif
|
||||||
Throttled = false;
|
Throttled = false;
|
||||||
|
|
||||||
var clients = GetPlayersAsList();
|
foreach(var client in polledClients)
|
||||||
foreach (var client in clients)
|
|
||||||
{
|
{
|
||||||
// remove players that have disconnected
|
// todo: move out somehwere
|
||||||
if (!CurrentPlayers.Select(c => c.NetworkId).Contains(client.NetworkId))
|
var existingClient = Players[client.ClientNumber] ?? client;
|
||||||
{
|
existingClient.Ping = client.Ping;
|
||||||
// the log should already have started a disconnect event
|
existingClient.Score = client.Score;
|
||||||
if (client.State == Player.ClientState.Disconnecting)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var e = new GameEvent()
|
|
||||||
{
|
|
||||||
Type = GameEvent.EventType.Disconnect,
|
|
||||||
Origin = client,
|
|
||||||
Owner = this
|
|
||||||
};
|
|
||||||
|
|
||||||
client.State = Player.ClientState.Disconnecting;
|
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
|
||||||
// todo: needed?
|
|
||||||
// wait until the disconnect event is complete
|
|
||||||
e.OnProcessed.Wait();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AuthQueue.AuthenticateClients(CurrentPlayers);
|
var disconnectingClients = currentClients.Except(polledClients);
|
||||||
|
var connectingClients = polledClients.Except(currentClients);
|
||||||
|
|
||||||
foreach (var c in AuthQueue.GetAuthenticatedClients())
|
return new List<Player>[] { connectingClients.ToList(), disconnectingClients.ToList() };
|
||||||
{
|
|
||||||
await AddPlayer(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CurrentPlayers.Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
@ -621,7 +593,48 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int polledPlayerCount = await PollPlayersAsync();
|
var polledClients = await PollPlayersAsync();
|
||||||
|
var waiterList = new List<ManualResetEventSlim>();
|
||||||
|
|
||||||
|
foreach (var disconnectingClient in polledClients[1])
|
||||||
|
{
|
||||||
|
if (disconnectingClient.State == Player.ClientState.Disconnecting)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Disconnect,
|
||||||
|
Origin = disconnectingClient,
|
||||||
|
Owner = this
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
// wait until the disconnect event is complete
|
||||||
|
// because we don't want to try to fill up a slot that's not empty yet
|
||||||
|
waiterList.Add(e.OnProcessed);
|
||||||
|
}
|
||||||
|
// wait for all the disconnect tasks to finish
|
||||||
|
await Task.WhenAll(waiterList.Select(t => Task.Run(() => t.Wait(5000))));
|
||||||
|
|
||||||
|
waiterList.Clear();
|
||||||
|
// this are our new connecting clients
|
||||||
|
foreach (var client in polledClients[0])
|
||||||
|
{
|
||||||
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Connect,
|
||||||
|
Origin = client,
|
||||||
|
Owner = this
|
||||||
|
};
|
||||||
|
|
||||||
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
waiterList.Add(e.OnProcessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for all the connect tasks to finish
|
||||||
|
await Task.WhenAll(waiterList.Select(t => Task.Run(() => t.Wait())));
|
||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
{
|
{
|
||||||
@ -793,7 +806,7 @@ namespace IW4MAdmin
|
|||||||
CustomCallback = await ScriptLoaded();
|
CustomCallback = await ScriptLoaded();
|
||||||
string mainPath = EventParser.GetGameDir();
|
string mainPath = EventParser.GetGameDir();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II";
|
basepath.Value = @"";
|
||||||
#endif
|
#endif
|
||||||
string logPath;
|
string logPath;
|
||||||
if (GameName == Game.IW5)
|
if (GameName == Game.IW5)
|
||||||
|
@ -831,7 +831,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
double currentKDR = clientStats.SessionDeaths == 0 ? clientStats.SessionKills : clientStats.SessionKills / clientStats.SessionDeaths;
|
double currentKDR = clientStats.SessionDeaths == 0 ? clientStats.SessionKills : clientStats.SessionKills / clientStats.SessionDeaths;
|
||||||
double alpha = Math.Sqrt(2) / Math.Min(600, clientStats.Kills + clientStats.Deaths);
|
double alpha = Math.Sqrt(2) / Math.Min(600, clientStats.Kills + clientStats.Deaths);
|
||||||
clientStats.RollingWeightedKDR = (alpha * currentKDR) + (1.0 - alpha) * clientStats.KDR;
|
clientStats.RollingWeightedKDR = (alpha * currentKDR) + (1.0 - alpha) * clientStats.KDR;
|
||||||
double KDRWeight = Math.Round(Math.Pow(clientStats.RollingWeightedKDR, 1.637 / Math.E), 3);
|
double KDRWeight = clientStats.RollingWeightedKDR != 0 ? Math.Round(Math.Pow(clientStats.RollingWeightedKDR, 1.637 / Math.E), 3) : 0;
|
||||||
|
|
||||||
// calculate the weight of the new play time against last 10 hours of gameplay
|
// calculate the weight of the new play time against last 10 hours of gameplay
|
||||||
int totalPlayTime = (clientStats.TimePlayed == 0) ?
|
int totalPlayTime = (clientStats.TimePlayed == 0) ?
|
||||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
|
using SharedLibraryCore.Objects;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins
|
namespace IW4MAdmin.Plugins
|
||||||
{
|
{
|
||||||
@ -19,34 +20,85 @@ namespace IW4MAdmin.Plugins
|
|||||||
|
|
||||||
public async Task OnEventAsync(GameEvent E, Server S)
|
public async Task OnEventAsync(GameEvent E, Server S)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
if (E.Type == GameEvent.EventType.Start)
|
if (E.Type == GameEvent.EventType.Start)
|
||||||
{
|
{
|
||||||
#region PLAYER_HISTORY
|
#region UNIT_TEST_LOG_CONNECT
|
||||||
var rand = new Random(GetHashCode());
|
for (int i = 1; i <= 8; i++)
|
||||||
var time = DateTime.UtcNow;
|
{
|
||||||
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Join,
|
||||||
|
Origin = new Player()
|
||||||
|
{
|
||||||
|
Name = $"Player{i}",
|
||||||
|
NetworkId = i,
|
||||||
|
ClientNumber = i - 1
|
||||||
|
},
|
||||||
|
Owner = S
|
||||||
|
};
|
||||||
|
|
||||||
await Task.Run(() =>
|
S.Manager.GetEventHandler().AddEvent(e);
|
||||||
{
|
e.OnProcessed.Wait();
|
||||||
if (S.PlayerHistory.Count > 0)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
while (S.PlayerHistory.Count < 144)
|
S.Logger.WriteAssert(S.ClientNum == 8, "UNIT_TEST_LOG_CONNECT failed client num check");
|
||||||
{
|
|
||||||
S.PlayerHistory.Enqueue(new PlayerHistory(time, rand.Next(7, 18)));
|
|
||||||
time = time.AddMinutes(PlayerHistory.UpdateInterval);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PLUGIN_INFO
|
#region UNIT_TEST_RCON_AUTHENTICATE
|
||||||
Console.WriteLine("|Name |Alias|Description |Requires Target|Syntax |Required Level|");
|
for (int i = 1; i <= 8; i++)
|
||||||
Console.WriteLine("|--------------| -----| --------------------------------------------------------| -----------------| -------------| ----------------|");
|
|
||||||
foreach (var command in S.Manager.GetCommands().OrderByDescending(c => c.Permission).ThenBy(c => c.Name))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($"|{command.Name}|{command.Alias}|{command.Description}|{command.RequiresTarget}|{command.Syntax.Substring(8).EscapeMarkdown()}|{command.Permission}|");
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Connect,
|
||||||
|
Origin = new Player()
|
||||||
|
{
|
||||||
|
Name = $"Player{i}",
|
||||||
|
NetworkId = i,
|
||||||
|
ClientNumber = i - 1,
|
||||||
|
IPAddress = i,
|
||||||
|
Ping = 50,
|
||||||
|
CurrentServer = S
|
||||||
|
},
|
||||||
|
Owner = S,
|
||||||
|
};
|
||||||
|
|
||||||
|
S.Manager.GetEventHandler().AddEvent(e);
|
||||||
|
e.OnProcessed.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
S.Logger.WriteAssert(S.GetPlayersAsList().Count(p => p.State == Player.ClientState.Connected) == 8,
|
||||||
|
"UNIT_TEST_RCON_AUTHENTICATE failed client num connected state check");
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
//if (E.Type == GameEvent.EventType.Start)
|
||||||
|
//{
|
||||||
|
// #region PLAYER_HISTORY
|
||||||
|
// var rand = new Random(GetHashCode());
|
||||||
|
// var time = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// await Task.Run(() =>
|
||||||
|
// {
|
||||||
|
// if (S.PlayerHistory.Count > 0)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// while (S.PlayerHistory.Count < 144)
|
||||||
|
// {
|
||||||
|
// S.PlayerHistory.Enqueue(new PlayerHistory(time, rand.Next(7, 18)));
|
||||||
|
// time = time.AddMinutes(PlayerHistory.UpdateInterval);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region PLUGIN_INFO
|
||||||
|
// Console.WriteLine("|Name |Alias|Description |Requires Target|Syntax |Required Level|");
|
||||||
|
// Console.WriteLine("|--------------| -----| --------------------------------------------------------| -----------------| -------------| ----------------|");
|
||||||
|
// foreach (var command in S.Manager.GetCommands().OrderByDescending(c => c.Permission).ThenBy(c => c.Name))
|
||||||
|
// {
|
||||||
|
// Console.WriteLine($"|{command.Name}|{command.Alias}|{command.Description}|{command.RequiresTarget}|{command.Syntax.Substring(8).EscapeMarkdown()}|{command.Permission}|");
|
||||||
|
// }
|
||||||
|
// #endregion
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnLoadAsync(IManager manager) => Task.CompletedTask;
|
public Task OnLoadAsync(IManager manager) => Task.CompletedTask;
|
||||||
@ -54,84 +106,84 @@ namespace IW4MAdmin.Plugins
|
|||||||
public Task OnTickAsync(Server S)
|
public Task OnTickAsync(Server S)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
/*
|
/*
|
||||||
if ((DateTime.Now - Interval).TotalSeconds > 1)
|
if ((DateTime.Now - Interval).TotalSeconds > 1)
|
||||||
{
|
{
|
||||||
var rand = new Random();
|
var rand = new Random();
|
||||||
int index = rand.Next(0, 17);
|
int index = rand.Next(0, 17);
|
||||||
var p = new Player()
|
var p = new Player()
|
||||||
{
|
{
|
||||||
Name = $"Test_{index}",
|
Name = $"Test_{index}",
|
||||||
NetworkId = (long)$"_test_{index}".GetHashCode(),
|
NetworkId = (long)$"_test_{index}".GetHashCode(),
|
||||||
ClientNumber = index,
|
ClientNumber = index,
|
||||||
Ping = 1,
|
Ping = 1,
|
||||||
IPAddress = $"127.0.0.{index}".ConvertToIP()
|
IPAddress = $"127.0.0.{index}".ConvertToIP()
|
||||||
};
|
};
|
||||||
|
|
||||||
if (S.Players.ElementAt(index) != null)
|
if (S.Players.ElementAt(index) != null)
|
||||||
await S.RemovePlayer(index);
|
await S.RemovePlayer(index);
|
||||||
// await S.AddPlayer(p);
|
// await S.AddPlayer(p);
|
||||||
|
|
||||||
|
|
||||||
Interval = DateTime.Now;
|
Interval = DateTime.Now;
|
||||||
if (S.ClientNum > 0)
|
if (S.ClientNum > 0)
|
||||||
{
|
{
|
||||||
var victimPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)];
|
var victimPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)];
|
||||||
var attackerPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)];
|
var attackerPlayer = S.Players.Where(pl => pl != null).ToList()[rand.Next(0, S.ClientNum - 1)];
|
||||||
|
|
||||||
await S.ExecuteEvent(new Event(Event.GType.Say, $"test_{attackerPlayer.ClientNumber}", victimPlayer, attackerPlayer, S));
|
await S.ExecuteEvent(new Event(Event.GType.Say, $"test_{attackerPlayer.ClientNumber}", victimPlayer, attackerPlayer, S));
|
||||||
|
|
||||||
string[] eventLine = null;
|
string[] eventLine = null;
|
||||||
|
|
||||||
for (int i = 0; i < 1; i++)
|
for (int i = 0; i < 1; i++)
|
||||||
{
|
{
|
||||||
if (S.GameName == Server.Game.IW4)
|
if (S.GameName == Server.Game.IW4)
|
||||||
{
|
{
|
||||||
|
|
||||||
// attackerID ; victimID ; attackerOrigin ; victimOrigin ; Damage ; Weapon ; hitLocation ; meansOfDeath
|
// attackerID ; victimID ; attackerOrigin ; victimOrigin ; Damage ; Weapon ; hitLocation ; meansOfDeath
|
||||||
var minimapInfo = StatsPlugin.MinimapConfig.IW4Minimaps().MapInfo.FirstOrDefault(m => m.MapName == S.CurrentMap.Name);
|
var minimapInfo = StatsPlugin.MinimapConfig.IW4Minimaps().MapInfo.FirstOrDefault(m => m.MapName == S.CurrentMap.Name);
|
||||||
if (minimapInfo == null)
|
if (minimapInfo == null)
|
||||||
return;
|
return;
|
||||||
eventLine = new string[]
|
eventLine = new string[]
|
||||||
|
{
|
||||||
|
"ScriptKill",
|
||||||
|
attackerPlayer.NetworkId.ToString(),
|
||||||
|
victimPlayer.NetworkId.ToString(),
|
||||||
|
new Vector3(rand.Next(minimapInfo.MaxRight, minimapInfo.MaxLeft), rand.Next(minimapInfo.MaxBottom, minimapInfo.MaxTop), rand.Next(0, 100)).ToString(),
|
||||||
|
new Vector3(rand.Next(minimapInfo.MaxRight, minimapInfo.MaxLeft), rand.Next(minimapInfo.MaxBottom, minimapInfo.MaxTop), rand.Next(0, 100)).ToString(),
|
||||||
|
rand.Next(50, 105).ToString(),
|
||||||
|
((StatsPlugin.IW4Info.WeaponName)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.WeaponName)).Length - 1)).ToString(),
|
||||||
|
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(),
|
||||||
|
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eventLine = new string[]
|
||||||
{
|
{
|
||||||
"ScriptKill",
|
"K",
|
||||||
attackerPlayer.NetworkId.ToString(),
|
victimPlayer.NetworkId.ToString(),
|
||||||
victimPlayer.NetworkId.ToString(),
|
victimPlayer.ClientNumber.ToString(),
|
||||||
new Vector3(rand.Next(minimapInfo.MaxRight, minimapInfo.MaxLeft), rand.Next(minimapInfo.MaxBottom, minimapInfo.MaxTop), rand.Next(0, 100)).ToString(),
|
rand.Next(0, 1) == 0 ? "allies" : "axis",
|
||||||
new Vector3(rand.Next(minimapInfo.MaxRight, minimapInfo.MaxLeft), rand.Next(minimapInfo.MaxBottom, minimapInfo.MaxTop), rand.Next(0, 100)).ToString(),
|
victimPlayer.Name,
|
||||||
rand.Next(50, 105).ToString(),
|
attackerPlayer.NetworkId.ToString(),
|
||||||
((StatsPlugin.IW4Info.WeaponName)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.WeaponName)).Length - 1)).ToString(),
|
attackerPlayer.ClientNumber.ToString(),
|
||||||
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(),
|
rand.Next(0, 1) == 0 ? "allies" : "axis",
|
||||||
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString()
|
attackerPlayer.Name.ToString(),
|
||||||
|
((StatsPlugin.IW4Info.WeaponName)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.WeaponName)).Length - 1)).ToString(), // Weapon
|
||||||
|
rand.Next(50, 105).ToString(), // Damage
|
||||||
|
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString(), // Means of Death
|
||||||
|
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(), // Hit Location
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
var _event = Event.ParseEventString(eventLine, S);
|
||||||
else
|
await S.ExecuteEvent(_event);
|
||||||
{
|
}
|
||||||
eventLine = new string[]
|
}
|
||||||
{
|
}
|
||||||
"K",
|
*/
|
||||||
victimPlayer.NetworkId.ToString(),
|
|
||||||
victimPlayer.ClientNumber.ToString(),
|
|
||||||
rand.Next(0, 1) == 0 ? "allies" : "axis",
|
|
||||||
victimPlayer.Name,
|
|
||||||
attackerPlayer.NetworkId.ToString(),
|
|
||||||
attackerPlayer.ClientNumber.ToString(),
|
|
||||||
rand.Next(0, 1) == 0 ? "allies" : "axis",
|
|
||||||
attackerPlayer.Name.ToString(),
|
|
||||||
((StatsPlugin.IW4Info.WeaponName)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.WeaponName)).Length - 1)).ToString(), // Weapon
|
|
||||||
rand.Next(50, 105).ToString(), // Damage
|
|
||||||
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString(), // Means of Death
|
|
||||||
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(), // Hit Location
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var _event = Event.ParseEventString(eventLine, S);
|
|
||||||
await S.ExecuteEvent(_event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnUnloadAsync() => Task.CompletedTask;
|
public Task OnUnloadAsync() => Task.CompletedTask;
|
||||||
|
@ -40,6 +40,8 @@ namespace SharedLibraryCore
|
|||||||
Damage,
|
Damage,
|
||||||
Kill,
|
Kill,
|
||||||
JoinTeam,
|
JoinTeam,
|
||||||
|
|
||||||
|
StatusUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameEvent(EventType t, string d, Player O, Player T, Server S)
|
public GameEvent(EventType t, string d, Player O, Player T, Server S)
|
||||||
@ -86,9 +88,9 @@ namespace SharedLibraryCore
|
|||||||
public static bool ShouldOriginEventBeDelayed(GameEvent queuedEvent)
|
public static bool ShouldOriginEventBeDelayed(GameEvent queuedEvent)
|
||||||
{
|
{
|
||||||
return queuedEvent.Origin != null &&
|
return queuedEvent.Origin != null &&
|
||||||
!queuedEvent.Origin.IsAuthenticated &&
|
|
||||||
queuedEvent.Origin.State != Player.ClientState.Connected &&
|
queuedEvent.Origin.State != Player.ClientState.Connected &&
|
||||||
// we want to allow join and quit events
|
// we want to allow join and quit events
|
||||||
|
queuedEvent.Type != EventType.Connect &&
|
||||||
queuedEvent.Type != EventType.Join &&
|
queuedEvent.Type != EventType.Join &&
|
||||||
queuedEvent.Type != EventType.Quit &&
|
queuedEvent.Type != EventType.Quit &&
|
||||||
// we don't care about unknown events
|
// we don't care about unknown events
|
||||||
@ -104,7 +106,6 @@ namespace SharedLibraryCore
|
|||||||
public static bool ShouldTargetEventBeDelayed(GameEvent queuedEvent)
|
public static bool ShouldTargetEventBeDelayed(GameEvent queuedEvent)
|
||||||
{
|
{
|
||||||
return queuedEvent.Target != null &&
|
return queuedEvent.Target != null &&
|
||||||
!queuedEvent.Target.IsAuthenticated &&
|
|
||||||
queuedEvent.Target.State != Player.ClientState.Connected &&
|
queuedEvent.Target.State != Player.ClientState.Connected &&
|
||||||
queuedEvent.Target.NetworkId != 0;
|
queuedEvent.Target.NetworkId != 0;
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// Add a game event event to the queue to be processed
|
/// Add a game event event to the queue to be processed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gameEvent">Game event</param>
|
/// <param name="gameEvent">Game event</param>
|
||||||
/// <param name="delayedExecution">don't signal that an event has been aded</param>
|
void AddEvent(GameEvent gameEvent);
|
||||||
void AddEvent(GameEvent gameEvent, bool delayedExecution = false);
|
|
||||||
/// <summary>
|
|
||||||
/// Get the next event to be processed
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Game event that needs to be processed</returns>
|
|
||||||
GameEvent GetNextEvent();
|
|
||||||
/// <summary>
|
|
||||||
/// If an event has output. Like executing a command wait until it's available
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>List of output strings</returns>
|
|
||||||
string[] GetEventOutput();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,5 +13,6 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
void WriteDebug(string msg);
|
void WriteDebug(string msg);
|
||||||
void WriteWarning(string msg);
|
void WriteWarning(string msg);
|
||||||
void WriteError(string msg);
|
void WriteError(string msg);
|
||||||
|
void WriteAssert(bool condition, string msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
public interface IManager
|
public interface IManager
|
||||||
{
|
{
|
||||||
Task Init();
|
Task Init();
|
||||||
Task Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
ILogger GetLogger();
|
ILogger GetLogger();
|
||||||
IList<Server> GetServers();
|
IList<Server> GetServers();
|
||||||
|
@ -11,8 +11,24 @@ namespace SharedLibraryCore.Objects
|
|||||||
{
|
{
|
||||||
public enum ClientState
|
public enum ClientState
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// represents when the client has been detected as joining
|
||||||
|
/// by the log file, but has not be authenticated by RCon
|
||||||
|
/// </summary>
|
||||||
Connecting,
|
Connecting,
|
||||||
|
/// <summary>
|
||||||
|
/// represents when the client has been parsed by RCon,
|
||||||
|
/// but has not been validated against the database
|
||||||
|
/// </summary>
|
||||||
|
Authenticated,
|
||||||
|
/// <summary>
|
||||||
|
/// represents when the client has been authenticated by RCon
|
||||||
|
/// and validated by the database
|
||||||
|
/// </summary>
|
||||||
Connected,
|
Connected,
|
||||||
|
/// <summary>
|
||||||
|
/// represents when the client is leaving (either through RCon or log file)
|
||||||
|
/// </summary>
|
||||||
Disconnecting,
|
Disconnecting,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +133,6 @@ namespace SharedLibraryCore.Objects
|
|||||||
set { _name = value; }
|
set { _name = value; }
|
||||||
}
|
}
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsAuthenticated { get; set; }
|
|
||||||
[NotMapped]
|
|
||||||
public ClientState State { get; set; }
|
public ClientState State { get; set; }
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public Queue<GameEvent> DelayedEvents { get; set; }
|
public Queue<GameEvent> DelayedEvents { get; set; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user