think I finished reworking the event system
added http log reading support for debugging remotely started working on unit test framework
This commit is contained in:
parent
56cb8c50e7
commit
bbefd53db4
@ -140,26 +140,26 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
}
|
||||
}
|
||||
|
||||
if (eventType == "Q")
|
||||
{
|
||||
var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$");
|
||||
if (regexMatch.Success)
|
||||
{
|
||||
return new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Quit,
|
||||
Data = logLine,
|
||||
Owner = server,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||
ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||
State = Player.ClientState.Connecting
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
//if (eventType == "Q")
|
||||
//{
|
||||
// var regexMatch = Regex.Match(logLine, @"^(Q;)(.{1,32});([0-9]+);(.*)$");
|
||||
// if (regexMatch.Success)
|
||||
// {
|
||||
// return new GameEvent()
|
||||
// {
|
||||
// Type = GameEvent.EventType.Quit,
|
||||
// Data = logLine,
|
||||
// Owner = server,
|
||||
// Origin = new Player()
|
||||
// {
|
||||
// Name = regexMatch.Groups[4].ToString().StripColors(),
|
||||
// NetworkId = regexMatch.Groups[2].ToString().ConvertLong(),
|
||||
// ClientNumber = Convert.ToInt32(regexMatch.Groups[3].ToString()),
|
||||
// State = Player.ClientState.Connecting
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//}
|
||||
|
||||
if (eventType.Contains("ExitLevel"))
|
||||
{
|
||||
|
@ -6,11 +6,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace IW4MAdmin.Application.IO
|
||||
{
|
||||
class GameLogEvent
|
||||
class GameLogEventDetection
|
||||
{
|
||||
Server Server;
|
||||
long PreviousFileSize;
|
||||
GameLogReader Reader;
|
||||
IGameLogReader Reader;
|
||||
readonly string GameLogFile;
|
||||
|
||||
class EventState
|
||||
@ -19,10 +19,18 @@ namespace IW4MAdmin.Application.IO
|
||||
public string ServerId { get; set; }
|
||||
}
|
||||
|
||||
public GameLogEvent(Server server, string gameLogPath, string gameLogName)
|
||||
public GameLogEventDetection(Server server, string gameLogPath, string gameLogName)
|
||||
{
|
||||
GameLogFile = gameLogPath;
|
||||
// todo: abtract this more
|
||||
if (gameLogPath.StartsWith("http"))
|
||||
{
|
||||
Reader = new GameLogReaderHttp(gameLogPath, server.EventParser);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reader = new GameLogReader(gameLogPath, server.EventParser);
|
||||
}
|
||||
Server = server;
|
||||
|
||||
Task.Run(async () =>
|
||||
@ -44,7 +52,7 @@ namespace IW4MAdmin.Application.IO
|
||||
|
||||
private void OnEvent(object state)
|
||||
{
|
||||
long newLength = new FileInfo(GameLogFile).Length;
|
||||
long newLength = Reader.Length;
|
||||
|
||||
try
|
||||
{
|
@ -7,11 +7,15 @@ using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Application.IO
|
||||
{
|
||||
class GameLogReader
|
||||
class GameLogReader : IGameLogReader
|
||||
{
|
||||
IEventParser Parser;
|
||||
readonly string LogFile;
|
||||
|
||||
public long Length => new FileInfo(LogFile).Length;
|
||||
|
||||
public int UpdateInterval => 100;
|
||||
|
||||
public GameLogReader(string logFile, IEventParser parser)
|
||||
{
|
||||
LogFile = logFile;
|
||||
|
84
Application/IO/GameLogReaderHttp.cs
Normal file
84
Application/IO/GameLogReaderHttp.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace IW4MAdmin.Application.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// provides capibility of reading log files over HTTP
|
||||
/// </summary>
|
||||
class GameLogReaderHttp : IGameLogReader
|
||||
{
|
||||
readonly IEventParser Parser;
|
||||
readonly string LogFile;
|
||||
|
||||
public GameLogReaderHttp(string logFile, IEventParser parser)
|
||||
{
|
||||
LogFile = logFile;
|
||||
Parser = parser;
|
||||
}
|
||||
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var cl = new HttpClient())
|
||||
{
|
||||
using (var re = cl.GetAsync($"{LogFile}?length=1").Result)
|
||||
{
|
||||
using (var content = re.Content)
|
||||
{
|
||||
return Convert.ToInt64(content.ReadAsStringAsync().Result ?? "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int UpdateInterval => 1000;
|
||||
|
||||
public ICollection<GameEvent> EventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||
{
|
||||
string log;
|
||||
using (var cl = new HttpClient())
|
||||
{
|
||||
using (var re = cl.GetAsync($"{LogFile}?start={fileSizeDiff}").Result)
|
||||
{
|
||||
using (var content = re.Content)
|
||||
{
|
||||
log = content.ReadAsStringAsync().Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<GameEvent> events = new List<GameEvent>();
|
||||
|
||||
// parse each line
|
||||
foreach (string eventLine in log.Split(Environment.NewLine))
|
||||
{
|
||||
if (eventLine.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// todo: catch elsewhere
|
||||
events.Add(Parser.GetEvent(server, eventLine));
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Program.ServerManager.GetLogger().WriteWarning("Could not properly parse event line");
|
||||
Program.ServerManager.GetLogger().WriteDebug(e.Message);
|
||||
Program.ServerManager.GetLogger().WriteDebug(eventLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
}
|
||||
}
|
@ -50,9 +50,6 @@ namespace IW4MAdmin.Application
|
||||
Localization.Configure.Initialize(ServerManager.GetApplicationSettings().Configuration()?.CustomLocale);
|
||||
loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
|
||||
using (var db = new DatabaseContext(ServerManager.GetApplicationSettings().Configuration()?.ConnectionString))
|
||||
new ContextSeed(db).Seed().Wait();
|
||||
|
||||
var api = API.Master.Endpoint.Get();
|
||||
|
||||
var version = new API.Master.VersionInfo()
|
||||
|
@ -21,6 +21,7 @@ using Newtonsoft.Json.Linq;
|
||||
using System.Text;
|
||||
using IW4MAdmin.Application.API.Master;
|
||||
using System.Reflection;
|
||||
using SharedLibraryCore.Database;
|
||||
|
||||
namespace IW4MAdmin.Application
|
||||
{
|
||||
@ -36,7 +37,7 @@ namespace IW4MAdmin.Application
|
||||
// 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 OnServerEventEventHandler OnServerEvent { get; set; }
|
||||
public DateTime StartTime { get; private set; }
|
||||
|
||||
static ApplicationManager Instance;
|
||||
@ -46,10 +47,10 @@ namespace IW4MAdmin.Application
|
||||
ClientService ClientSvc;
|
||||
readonly AliasService AliasSvc;
|
||||
readonly PenaltyService PenaltySvc;
|
||||
BaseConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
||||
public BaseConfigurationHandler<ApplicationConfiguration> ConfigHandler;
|
||||
EventApi Api;
|
||||
GameEventHandler Handler;
|
||||
ManualResetEventSlim OnEvent;
|
||||
ManualResetEventSlim OnQuit;
|
||||
readonly IPageList PageList;
|
||||
|
||||
public class GameEventArgs : System.ComponentModel.AsyncCompletedEventArgs
|
||||
@ -78,7 +79,7 @@ namespace IW4MAdmin.Application
|
||||
//ServerEventOccurred += Api.OnServerEvent;
|
||||
ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("IW4MAdminSettings");
|
||||
StartTime = DateTime.UtcNow;
|
||||
OnEvent = new ManualResetEventSlim();
|
||||
OnQuit = new ManualResetEventSlim();
|
||||
PageList = new PageList();
|
||||
OnServerEvent += OnServerEventAsync;
|
||||
}
|
||||
@ -110,15 +111,16 @@ namespace IW4MAdmin.Application
|
||||
await newEvent.Owner.ExecuteEvent(newEvent);
|
||||
|
||||
//// todo: this is a hacky mess
|
||||
if (newEvent.Origin?.DelayedEvents?.Count > 0 &&
|
||||
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)
|
||||
while(events.Count > 0)
|
||||
{
|
||||
var e = events.Dequeue();
|
||||
|
||||
e.Origin = newEvent.Origin;
|
||||
// check if the target was assigned
|
||||
if (e.Target != null)
|
||||
@ -133,9 +135,12 @@ namespace IW4MAdmin.Application
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Logger.WriteDebug($"Adding delayed event of type {e.Type} for {e.Origin} back for processing");
|
||||
this.GetEventHandler().AddEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
Api.OnServerEvent(this, newEvent);
|
||||
#if DEBUG
|
||||
Logger.WriteDebug("Processed Event");
|
||||
#endif
|
||||
@ -248,6 +253,11 @@ namespace IW4MAdmin.Application
|
||||
Running = true;
|
||||
|
||||
#region DATABASE
|
||||
using (var db = new DatabaseContext(GetApplicationSettings().Configuration()?.ConnectionString))
|
||||
{
|
||||
await new ContextSeed(db).Seed();
|
||||
}
|
||||
|
||||
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
|
||||
.Select(c => new
|
||||
{
|
||||
@ -513,8 +523,8 @@ namespace IW4MAdmin.Application
|
||||
|
||||
while (Running)
|
||||
{
|
||||
OnEvent.Wait();
|
||||
OnEvent.Reset();
|
||||
OnQuit.Wait();
|
||||
OnQuit.Reset();
|
||||
}
|
||||
_servers.Clear();
|
||||
}
|
||||
@ -558,7 +568,7 @@ namespace IW4MAdmin.Application
|
||||
|
||||
public void SetHasEvent()
|
||||
{
|
||||
OnEvent.Set();
|
||||
OnQuit.Set();
|
||||
}
|
||||
|
||||
public IList<Assembly> GetPluginAssemblies() => SharedLibraryCore.Plugins.PluginImporter.PluginAssemblies;
|
||||
|
@ -117,7 +117,6 @@ namespace IW4MAdmin.Application.RconParsers
|
||||
IsBot = ip == 0,
|
||||
State = Player.ClientState.Connecting
|
||||
};
|
||||
|
||||
StatusPlayers.Add(P);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ using SharedLibraryCore.Objects;
|
||||
using SharedLibraryCore.RCon;
|
||||
using SharedLibraryCore.Exceptions;
|
||||
|
||||
namespace IW4MAdmin.WApplication.RconParsers
|
||||
namespace IW4MAdmin.Application.RconParsers
|
||||
{
|
||||
public class IW5MRConParser : IRConParser
|
||||
{
|
||||
|
@ -20,14 +20,13 @@ using IW4MAdmin.Application.RconParsers;
|
||||
using IW4MAdmin.Application.EventParsers;
|
||||
using IW4MAdmin.Application.IO;
|
||||
using IW4MAdmin.Application.Core;
|
||||
using IW4MAdmin.WApplication.RconParsers;
|
||||
|
||||
namespace IW4MAdmin
|
||||
{
|
||||
public class IW4MServer : Server
|
||||
{
|
||||
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
private GameLogEvent LogEvent;
|
||||
private GameLogEventDetection LogEvent;
|
||||
private ClientAuthentication AuthQueue;
|
||||
|
||||
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
|
||||
@ -56,8 +55,11 @@ namespace IW4MAdmin
|
||||
|
||||
public async Task OnPlayerJoined(Player logClient)
|
||||
{
|
||||
if (Players[logClient.ClientNumber] == null ||
|
||||
Players[logClient.ClientNumber].NetworkId != logClient.NetworkId)
|
||||
var existingClient = Players[logClient.ClientNumber];
|
||||
|
||||
if (existingClient == null ||
|
||||
(existingClient.NetworkId != logClient.NetworkId &&
|
||||
existingClient.State != Player.ClientState.Connected))
|
||||
{
|
||||
Logger.WriteDebug($"Log detected {logClient} joining");
|
||||
Players[logClient.ClientNumber] = logClient;
|
||||
@ -68,9 +70,8 @@ namespace IW4MAdmin
|
||||
|
||||
override public async Task<bool> AddPlayer(Player polledPlayer)
|
||||
{
|
||||
//if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
||||
// polledPlayer.Ping < 1 ||
|
||||
if (
|
||||
if ((polledPlayer.Ping == 999 && !polledPlayer.IsBot) ||
|
||||
polledPlayer.Ping < 1 ||
|
||||
polledPlayer.ClientNumber < 0)
|
||||
{
|
||||
//Logger.WriteDebug($"Skipping client not in connected state {P}");
|
||||
@ -186,6 +187,8 @@ namespace IW4MAdmin
|
||||
player.IsBot = polledPlayer.IsBot;
|
||||
player.Score = polledPlayer.Score;
|
||||
player.CurrentServer = this;
|
||||
|
||||
player.DelayedEvents = (Players[player.ClientNumber]?.DelayedEvents) ?? new Queue<GameEvent>();
|
||||
Players[player.ClientNumber] = player;
|
||||
|
||||
var activePenalties = await Manager.GetPenaltyService().GetActivePenaltiesAsync(player.AliasLinkId, player.IPAddress);
|
||||
@ -278,7 +281,6 @@ namespace IW4MAdmin
|
||||
public override async Task ExecuteEvent(GameEvent E)
|
||||
{
|
||||
bool canExecuteCommand = true;
|
||||
Manager.GetEventApi().OnServerEvent(this, E);
|
||||
await ProcessEvent(E);
|
||||
|
||||
Command C = null;
|
||||
@ -387,15 +389,16 @@ namespace IW4MAdmin
|
||||
}
|
||||
}
|
||||
|
||||
if (E.Type == GameEvent.EventType.Connect)
|
||||
else 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");
|
||||
E.Origin.State = Player.ClientState.Connecting;
|
||||
throw new ServerException("client didn't pass authorization, so we are discontinuing event");
|
||||
}
|
||||
// hack makes the event propgate with the correct info
|
||||
// hack: makes the event propgate with the correct info
|
||||
E.Origin = Players[E.Origin.ClientNumber];
|
||||
|
||||
ChatHistory.Add(new ChatInfo()
|
||||
@ -416,27 +419,27 @@ namespace IW4MAdmin
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Quit)
|
||||
{
|
||||
var origin = Players.FirstOrDefault(p => p != null && p.NetworkId == E.Origin.NetworkId);
|
||||
//var origin = Players.FirstOrDefault(p => p != null && p.NetworkId == E.Origin.NetworkId);
|
||||
|
||||
if (origin != null &&
|
||||
// we only want to forward the event if they are connected.
|
||||
origin.State == Player.ClientState.Connected)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Disconnect,
|
||||
Origin = origin,
|
||||
Owner = this
|
||||
};
|
||||
//if (origin != null &&
|
||||
// // we only want to forward the event if they are connected.
|
||||
// origin.State == Player.ClientState.Connected)
|
||||
//{
|
||||
// var e = new GameEvent()
|
||||
// {
|
||||
// Type = GameEvent.EventType.Disconnect,
|
||||
// Origin = origin,
|
||||
// Owner = this
|
||||
// };
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
}
|
||||
// Manager.GetEventHandler().AddEvent(e);
|
||||
//}
|
||||
|
||||
else if (origin != null &&
|
||||
origin.State != Player.ClientState.Connected)
|
||||
{
|
||||
await RemovePlayer(origin.ClientNumber);
|
||||
}
|
||||
//else if (origin != null &&
|
||||
// origin.State != Player.ClientState.Connected)
|
||||
//{
|
||||
// await RemovePlayer(origin.ClientNumber);
|
||||
//}
|
||||
}
|
||||
|
||||
else if (E.Type == GameEvent.EventType.Disconnect)
|
||||
@ -448,7 +451,13 @@ namespace IW4MAdmin
|
||||
Time = DateTime.UtcNow
|
||||
});
|
||||
|
||||
var currentState = E.Origin.State;
|
||||
await RemovePlayer(E.Origin.ClientNumber);
|
||||
|
||||
if (currentState != Player.ClientState.Connected)
|
||||
{
|
||||
throw new ServerException("Disconnecting player was not in a connected state");
|
||||
}
|
||||
}
|
||||
|
||||
if (E.Type == GameEvent.EventType.Say)
|
||||
@ -555,7 +564,7 @@ namespace IW4MAdmin
|
||||
#endif
|
||||
Throttled = false;
|
||||
|
||||
foreach(var client in polledClients)
|
||||
foreach (var client in polledClients)
|
||||
{
|
||||
// todo: move out somehwere
|
||||
var existingClient = Players[client.ClientNumber] ?? client;
|
||||
@ -564,7 +573,7 @@ namespace IW4MAdmin
|
||||
}
|
||||
|
||||
var disconnectingClients = currentClients.Except(polledClients);
|
||||
var connectingClients = polledClients.Except(currentClients);
|
||||
var connectingClients = polledClients.Except(currentClients.Where(c => c.State == Player.ClientState.Connected));
|
||||
|
||||
return new List<Player>[] { connectingClients.ToList(), disconnectingClients.ToList() };
|
||||
}
|
||||
@ -634,7 +643,7 @@ namespace IW4MAdmin
|
||||
}
|
||||
|
||||
// wait for all the connect tasks to finish
|
||||
await Task.WhenAll(waiterList.Select(t => Task.Run(() => t.Wait())));
|
||||
await Task.WhenAll(waiterList.Select(t => Task.Run(() => t.Wait(5000))));
|
||||
|
||||
if (ConnectionErrors > 0)
|
||||
{
|
||||
@ -806,10 +815,10 @@ namespace IW4MAdmin
|
||||
CustomCallback = await ScriptLoaded();
|
||||
string mainPath = EventParser.GetGameDir();
|
||||
#if DEBUG
|
||||
basepath.Value = @"";
|
||||
basepath.Value = @"D:\";
|
||||
#endif
|
||||
string logPath;
|
||||
if (GameName == Game.IW5)
|
||||
if (GameName == Game.IW5 || ServerConfig.ManualLogPath?.Length > 0)
|
||||
{
|
||||
logPath = ServerConfig.ManualLogPath;
|
||||
}
|
||||
@ -831,11 +840,13 @@ namespace IW4MAdmin
|
||||
Logger.WriteError($"{logPath} {loc["SERVER_ERROR_DNE"]}");
|
||||
#if !DEBUG
|
||||
throw new ServerException($"{loc["SERVER_ERROR_LOG"]} {logPath}");
|
||||
#else
|
||||
LogEvent = new GameLogEventDetection(this, logPath, logfile.Value);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
LogEvent = new GameLogEvent(this, logPath, logfile.Value);
|
||||
LogEvent = new GameLogEventDetection(this, logPath, logfile.Value);
|
||||
}
|
||||
|
||||
Logger.WriteInfo($"Log file is {logPath}");
|
||||
|
@ -625,7 +625,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
int individualClientRanking = await ctx.Set<EFRating>()
|
||||
.Where(c => c.ServerId == clientStats.ServerId)
|
||||
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
||||
.Where(r => r.ActivityAmount > 3600)
|
||||
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
||||
.Where(r => r.RatingHistory.Client.LastConnection > thirtyDaysAgo)
|
||||
.Where(c => c.RatingHistory.ClientId != client.ClientId)
|
||||
.Where(r => r.Newest)
|
||||
@ -670,11 +670,16 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
});
|
||||
|
||||
// weight the overall performance based on play time
|
||||
var performanceAverage = clientStatsList.Sum(p => (p.Performance * p.TimePlayed)) / clientStatsList.Sum(p => p.TimePlayed);
|
||||
double performanceAverage = clientStatsList.Sum(p => (p.Performance * p.TimePlayed)) / clientStatsList.Sum(p => p.TimePlayed);
|
||||
|
||||
if (double.IsNaN(performanceAverage))
|
||||
{
|
||||
performanceAverage = clientStatsList.Average(p => p.Performance);
|
||||
}
|
||||
|
||||
int overallClientRanking = await ctx.Set<EFRating>()
|
||||
.Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned)
|
||||
.Where(r => r.ActivityAmount > 3600)
|
||||
.Where(r => r.ActivityAmount > Plugin.Config.Configuration().TopPlayersMinPlayTime)
|
||||
.Where(r => r.RatingHistory.Client.LastConnection > thirtyDaysAgo)
|
||||
.Where(r => r.RatingHistory.ClientId != client.ClientId)
|
||||
.Where(r => r.ServerId == null)
|
||||
|
61
Plugins/Tests/ManagerFixture.cs
Normal file
61
Plugins/Tests/ManagerFixture.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using IW4MAdmin.Application;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
public class ManagerFixture : IDisposable
|
||||
{
|
||||
public ApplicationManager Manager { get; private set; }
|
||||
|
||||
public ManagerFixture()
|
||||
{
|
||||
|
||||
File.WriteAllText("test_mp.log", "TEST_LOG_FILE");
|
||||
|
||||
Manager = Program.ServerManager;
|
||||
|
||||
var config = new ApplicationConfiguration
|
||||
{
|
||||
Servers = new List<ServerConfiguration>()
|
||||
{
|
||||
new ServerConfiguration()
|
||||
{
|
||||
AutoMessages = new List<string>(),
|
||||
IPAddress = "127.0.0.1",
|
||||
Password = "test",
|
||||
Port = 28963,
|
||||
Rules = new List<string>(),
|
||||
ManualLogPath = "https://raidmax.org/IW4MAdmin/getlog.php"
|
||||
}
|
||||
},
|
||||
AutoMessages = new List<string>(),
|
||||
GlobalRules = new List<string>(),
|
||||
Maps = new List<MapConfiguration>(),
|
||||
RConPollRate = 10000
|
||||
};
|
||||
Manager.ConfigHandler = new BaseConfigurationHandler<ApplicationConfiguration>("Test.json");
|
||||
Manager.ConfigHandler.Set(config);
|
||||
|
||||
Manager.Init().Wait();
|
||||
Task.Run(() => Manager.Start());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Manager.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
[CollectionDefinition("ManagerCollection")]
|
||||
public class ManagerCollection : ICollectionFixture<ManagerFixture>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
194
Plugins/Tests/ManagerTests.cs
Normal file
194
Plugins/Tests/ManagerTests.cs
Normal file
@ -0,0 +1,194 @@
|
||||
using IW4MAdmin.Application;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Xunit;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
[Collection("ManagerCollection")]
|
||||
public class ManagerTests
|
||||
{
|
||||
readonly ApplicationManager Manager;
|
||||
|
||||
public ManagerTests(ManagerFixture fixture)
|
||||
{
|
||||
Manager = fixture.Manager;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AreCommandNamesUnique()
|
||||
{
|
||||
bool test = Manager.GetCommands().Count == Manager.GetCommands().Select(c => c.Name).Distinct().Count();
|
||||
Assert.True(test, "command names are not unique");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AreCommandAliasesUnique()
|
||||
{
|
||||
var mgr = IW4MAdmin.Application.Program.ServerManager;
|
||||
bool test = mgr.GetCommands().Count == mgr.GetCommands().Select(c => c.Alias).Distinct().Count();
|
||||
|
||||
Assert.True(test, "command aliases are not unique");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddAndRemoveClientsViaJoinShouldSucceed()
|
||||
{
|
||||
var server = Manager.GetServers().First();
|
||||
var waiters = new Queue<ManualResetEventSlim>();
|
||||
|
||||
int clientStartIndex = 4;
|
||||
int clientNum = 10;
|
||||
|
||||
for (int i = clientStartIndex; i < clientStartIndex + clientNum; i++)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Join,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = $"Player{i}",
|
||||
NetworkId = i,
|
||||
ClientNumber = i - 1
|
||||
},
|
||||
Owner = server
|
||||
};
|
||||
|
||||
server.Manager.GetEventHandler().AddEvent(e);
|
||||
waiters.Enqueue(e.OnProcessed);
|
||||
}
|
||||
|
||||
while (waiters.Count > 0)
|
||||
{
|
||||
waiters.Dequeue().Wait();
|
||||
}
|
||||
|
||||
Assert.True(server.ClientNum == clientNum, $"client num does not match added client num [{server.ClientNum}:{clientNum}]");
|
||||
|
||||
for (int i = clientStartIndex; i < clientStartIndex + clientNum; i++)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Disconnect,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = $"Player{i}",
|
||||
NetworkId = i,
|
||||
ClientNumber = i - 1
|
||||
},
|
||||
Owner = server
|
||||
};
|
||||
|
||||
server.Manager.GetEventHandler().AddEvent(e);
|
||||
waiters.Enqueue(e.OnProcessed);
|
||||
}
|
||||
|
||||
while (waiters.Count > 0)
|
||||
{
|
||||
waiters.Dequeue().Wait();
|
||||
}
|
||||
|
||||
Assert.True(server.ClientNum == 0, "there are still clients connected");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddAndRemoveClientsViaRconShouldSucceed()
|
||||
{
|
||||
var server = Manager.GetServers().First();
|
||||
var waiters = new Queue<ManualResetEventSlim>();
|
||||
|
||||
int clientIndexStart = 1;
|
||||
int clientNum = 8;
|
||||
|
||||
for (int i = clientIndexStart; i < clientNum + clientIndexStart; i++)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Connect,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = $"Player{i}",
|
||||
NetworkId = i,
|
||||
ClientNumber = i - 1,
|
||||
IPAddress = i,
|
||||
Ping = 50,
|
||||
CurrentServer = server
|
||||
},
|
||||
Owner = server,
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
waiters.Enqueue(e.OnProcessed);
|
||||
}
|
||||
|
||||
while (waiters.Count > 0)
|
||||
{
|
||||
waiters.Dequeue().Wait();
|
||||
}
|
||||
|
||||
int actualClientNum = server.GetPlayersAsList().Count(p => p.State == Player.ClientState.Connected);
|
||||
Assert.True(actualClientNum == clientNum, $"client connected states don't match [{actualClientNum}:{clientNum}");
|
||||
|
||||
for (int i = clientIndexStart; i < clientNum + clientIndexStart; i++)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Disconnect,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = $"Player{i}",
|
||||
NetworkId = i,
|
||||
ClientNumber = i - 1,
|
||||
IPAddress = i,
|
||||
Ping = 50,
|
||||
CurrentServer = server
|
||||
},
|
||||
Owner = server,
|
||||
};
|
||||
|
||||
Manager.GetEventHandler().AddEvent(e);
|
||||
waiters.Enqueue(e.OnProcessed);
|
||||
}
|
||||
|
||||
while (waiters.Count > 0)
|
||||
{
|
||||
waiters.Dequeue().Wait();
|
||||
}
|
||||
|
||||
actualClientNum = server.ClientNum;
|
||||
Assert.True(actualClientNum == 0, "there are clients still connected");
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void AddClientViaLog()
|
||||
{
|
||||
var resetEvent = new ManualResetEventSlim();
|
||||
resetEvent.Reset();
|
||||
|
||||
Manager.OnServerEvent += (sender, eventArgs) =>
|
||||
{
|
||||
if (eventArgs.Event.Type == GameEvent.EventType.Join)
|
||||
{
|
||||
eventArgs.Event.OnProcessed.Wait();
|
||||
Assert.True(false);
|
||||
}
|
||||
};
|
||||
|
||||
File.AppendAllText("test_mp.log", " 2:33 J;224b3d0bc64ab4f9;0;goober");
|
||||
|
||||
|
||||
resetEvent.Wait(5000);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,192 +0,0 @@
|
||||
#if DEBUG
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Objects;
|
||||
|
||||
namespace IW4MAdmin.Plugins
|
||||
{
|
||||
public class Tests : IPlugin
|
||||
{
|
||||
public string Name => "Dev Tests";
|
||||
|
||||
public float Version => 0.1f;
|
||||
|
||||
public string Author => "RaidMax";
|
||||
|
||||
public async Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
return;
|
||||
if (E.Type == GameEvent.EventType.Start)
|
||||
{
|
||||
#region UNIT_TEST_LOG_CONNECT
|
||||
for (int i = 1; i <= 8; i++)
|
||||
{
|
||||
var e = new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Join,
|
||||
Origin = new Player()
|
||||
{
|
||||
Name = $"Player{i}",
|
||||
NetworkId = i,
|
||||
ClientNumber = i - 1
|
||||
},
|
||||
Owner = S
|
||||
};
|
||||
|
||||
S.Manager.GetEventHandler().AddEvent(e);
|
||||
e.OnProcessed.Wait();
|
||||
}
|
||||
|
||||
S.Logger.WriteAssert(S.ClientNum == 8, "UNIT_TEST_LOG_CONNECT failed client num check");
|
||||
#endregion
|
||||
|
||||
#region UNIT_TEST_RCON_AUTHENTICATE
|
||||
for (int i = 1; i <= 8; i++)
|
||||
{
|
||||
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
|
||||
}
|
||||
//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 OnTickAsync(Server S)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
/*
|
||||
if ((DateTime.Now - Interval).TotalSeconds > 1)
|
||||
{
|
||||
var rand = new Random();
|
||||
int index = rand.Next(0, 17);
|
||||
var p = new Player()
|
||||
{
|
||||
Name = $"Test_{index}",
|
||||
NetworkId = (long)$"_test_{index}".GetHashCode(),
|
||||
ClientNumber = index,
|
||||
Ping = 1,
|
||||
IPAddress = $"127.0.0.{index}".ConvertToIP()
|
||||
};
|
||||
|
||||
if (S.Players.ElementAt(index) != null)
|
||||
await S.RemovePlayer(index);
|
||||
// await S.AddPlayer(p);
|
||||
|
||||
|
||||
Interval = DateTime.Now;
|
||||
if (S.ClientNum > 0)
|
||||
{
|
||||
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)];
|
||||
|
||||
await S.ExecuteEvent(new Event(Event.GType.Say, $"test_{attackerPlayer.ClientNumber}", victimPlayer, attackerPlayer, S));
|
||||
|
||||
string[] eventLine = null;
|
||||
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
if (S.GameName == Server.Game.IW4)
|
||||
{
|
||||
|
||||
// attackerID ; victimID ; attackerOrigin ; victimOrigin ; Damage ; Weapon ; hitLocation ; meansOfDeath
|
||||
var minimapInfo = StatsPlugin.MinimapConfig.IW4Minimaps().MapInfo.FirstOrDefault(m => m.MapName == S.CurrentMap.Name);
|
||||
if (minimapInfo == null)
|
||||
return;
|
||||
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[]
|
||||
{
|
||||
"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;
|
||||
}
|
||||
}
|
||||
#endif
|
10
Plugins/Tests/ServerTests.cs
Normal file
10
Plugins/Tests/ServerTests.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
class ServerTests
|
||||
{
|
||||
}
|
||||
}
|
@ -11,16 +11,18 @@
|
||||
<DefineConstants>TRACE;DEBUG;NETCOREAPP2_0</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="copy "$(TargetPath)" "$(SolutionDir)BUILD\Plugins"" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Application\Application.csproj" />
|
||||
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Update="Microsoft.NETCore.App"/>
|
||||
<PackageReference Update="Microsoft.NETCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -112,7 +112,7 @@ If you wish to further customize your experience of **IW4MAdmin**, the following
|
||||
* `{{TOTALPLAYTIME}}` — displays the cumulative play time (in man-hours) on all monitored servers
|
||||
* `{{VERSION}}` — displays the version of **IW4MAdmin**
|
||||
* `{{ADMINS}}` — displays the currently connected and *unmasked* privileged users online
|
||||
* `{{NEXTMAP}} &dmash; displays the next map in rotation
|
||||
* `{{NEXTMAP}}` — displays the next map and gametype in rotation
|
||||
|
||||
`GlobalRules`
|
||||
* Specifies the list of rules that apply to **all** servers`
|
||||
@ -120,7 +120,7 @@ If you wish to further customize your experience of **IW4MAdmin**, the following
|
||||
`Maps`
|
||||
* Specifies the list of maps for each supported game
|
||||
* `Name`
|
||||
* Specifies the name of the map as returned by the game
|
||||
* Specifies the name of the map as returned by the game (usually the file name sans the file extension)
|
||||
* `Alias`
|
||||
* Specifies the display name of the map (as seen while loading in)
|
||||
___
|
||||
@ -181,7 +181,7 @@ All players are identified 5 separate ways
|
||||
2. `IP` - The player's IP Address
|
||||
3. `Client ID` - The internal reference to a player, generated by **IW4MAdmin**
|
||||
4. `Name` - The visible player name as it appears in game
|
||||
5. `Client Number` - The slot the client client occupies on the server. The number ranges between 0 and the max number of clients allowed on the server
|
||||
5. `Client Number` - The slot the client occupies on a server. (The number ranges between 0 and the max number of clients allowed on the server)
|
||||
|
||||
For most commands players are identified by their `Name`
|
||||
However, if they are currently offline, or their name contains un-typable characters, their `Client ID` must be used
|
||||
|
@ -43,6 +43,8 @@ namespace SharedLibraryCore.Database
|
||||
currentPath = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
|
||||
$"{Path.DirectorySeparatorChar}{currentPath}" :
|
||||
currentPath;
|
||||
// todo: fix later
|
||||
|
||||
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = $"{currentPath}{Path.DirectorySeparatorChar}Database.db".Substring(6) };
|
||||
var connectionString = connectionStringBuilder.ToString();
|
||||
var connection = new SqliteConnection(connectionString);
|
||||
@ -98,22 +100,28 @@ namespace SharedLibraryCore.Database
|
||||
|
||||
// adapted from
|
||||
// https://aleemkhan.wordpress.com/2013/02/28/dynamically-adding-dbset-properties-in-dbcontext-for-entity-framework-code-first/
|
||||
#if !DEBUG
|
||||
foreach (string dllPath in Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins"))
|
||||
#else
|
||||
//#if DEBUG == TRUE
|
||||
// // foreach (string dllPath in Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins"))
|
||||
//#else
|
||||
//todo: fix the debug thingie for entity scanning
|
||||
IEnumerable<string> directoryFiles;
|
||||
try
|
||||
|
||||
string pluginDir = $@"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}Debug{Path.DirectorySeparatorChar}netcoreapp2.0{Path.DirectorySeparatorChar}Plugins";
|
||||
|
||||
if (!Directory.Exists(pluginDir))
|
||||
{
|
||||
directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}Debug{Path.DirectorySeparatorChar}netcoreapp2.0{Path.DirectorySeparatorChar}Plugins").Where(f => f.Contains(".dll"));
|
||||
pluginDir = $@"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}Plugins";
|
||||
|
||||
if (!Directory.Exists(pluginDir))
|
||||
{
|
||||
pluginDir = Utilities.OperatingDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception)
|
||||
{
|
||||
directoryFiles = Directory.GetFiles($@"{Environment.CurrentDirectory}{Path.DirectorySeparatorChar}Plugins").Where(f => f.Contains(".dll"));
|
||||
}
|
||||
directoryFiles = Directory.GetFiles(pluginDir).Where(f => f.Contains(".dll"));
|
||||
|
||||
foreach (string dllPath in directoryFiles)
|
||||
#endif
|
||||
//#endif
|
||||
{
|
||||
Assembly library;
|
||||
try
|
||||
|
@ -93,6 +93,7 @@ namespace SharedLibraryCore
|
||||
queuedEvent.Type != EventType.Connect &&
|
||||
queuedEvent.Type != EventType.Join &&
|
||||
queuedEvent.Type != EventType.Quit &&
|
||||
queuedEvent.Type != EventType.Disconnect &&
|
||||
// we don't care about unknown events
|
||||
queuedEvent.Origin.NetworkId != 0;
|
||||
}
|
||||
|
29
SharedLibraryCore/Interfaces/IGameLogReader.cs
Normal file
29
SharedLibraryCore/Interfaces/IGameLogReader.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// represents the abtraction of game log reading
|
||||
/// </summary>
|
||||
public interface IGameLogReader
|
||||
{
|
||||
/// <summary>
|
||||
/// get new events that have occured since the last poll
|
||||
/// </summary>
|
||||
/// <param name="server"></param>
|
||||
/// <param name="fileSizeDiff"></param>
|
||||
/// <param name="startPosition"></param>
|
||||
/// <returns></returns>
|
||||
ICollection<GameEvent> EventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
||||
/// <summary>
|
||||
/// how long the log file is
|
||||
/// </summary>
|
||||
long Length { get; }
|
||||
/// <summary>
|
||||
/// how often to poll the log file
|
||||
/// </summary>
|
||||
int UpdateInterval { get; }
|
||||
}
|
||||
}
|
@ -28,7 +28,10 @@ namespace SharedLibraryCore.Localization
|
||||
get
|
||||
{
|
||||
if (!Set.TryGetValue(key, out string value))
|
||||
throw new Exception($"Invalid locale key {key}");
|
||||
{
|
||||
// throw new Exception($"Invalid locale key {key}");
|
||||
return $"unknown locale key {key}";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,21 @@ namespace SharedLibraryCore.Plugins
|
||||
|
||||
public static bool Load(IManager Manager)
|
||||
{
|
||||
string[] dllFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.dll");
|
||||
string[] scriptFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.js");
|
||||
string pluginDir = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}";
|
||||
string[] dllFileNames = null;
|
||||
string[] scriptFileNames = null;
|
||||
|
||||
if (Directory.Exists(pluginDir))
|
||||
{
|
||||
dllFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.dll");
|
||||
scriptFileNames = Directory.GetFiles($"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}", "*.js");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
dllFileNames = new string[0];
|
||||
scriptFileNames = new string[0];
|
||||
}
|
||||
|
||||
if (dllFileNames.Length == 0 &&
|
||||
scriptFileNames.Length == 0)
|
||||
|
@ -40,7 +40,7 @@ namespace SharedLibraryCore.RCon
|
||||
ILogger Log;
|
||||
int FailedSends;
|
||||
int FailedReceives;
|
||||
DateTime LastQuery;
|
||||
static DateTime LastQuery;
|
||||
string response;
|
||||
|
||||
ManualResetEvent OnConnected;
|
||||
|
@ -18,7 +18,7 @@ namespace SharedLibraryCore
|
||||
{
|
||||
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
|
||||
public static Encoding EncodingType;
|
||||
public static Localization.Layout CurrentLocalization;
|
||||
public static Localization.Layout CurrentLocalization = new Localization.Layout(new Dictionary<string, string>());
|
||||
|
||||
public static string HttpRequest(string location, string header, string headerValue)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user