From 0ef306a60cef680d38757803c42d1f9f257a7b3b Mon Sep 17 00:00:00 2001 From: RaidMax Date: Mon, 12 Jun 2017 13:50:00 -0400 Subject: [PATCH] Cleaned up some code and adhered closer to the Microsoft code standards. --- Admin/IW4M ADMIN.csproj | 2 +- Admin/Kayak.cs | 7 +- Admin/Logger.cs | 4 +- Admin/Main.cs | 3 +- Admin/Manager.cs | 16 +- Admin/Server.cs | 64 ++- Admin/{Config.cs => ServerConfig.cs} | 6 +- Admin/WebService.cs | 370 ++++++++++-------- Admin/lib/SharedLibrary.dll | Bin 97280 -> 102912 bytes Plugins/EventAPI/Plugin.cs | 58 +-- Plugins/MessageBoard/Forum.cs | 246 ++++++------ .../Fakes/System.Data.SQLite.fakes | Bin 0 -> 252 bytes Plugins/SimpleStats/Plugin.cs | 32 +- Plugins/VoteMap/Plugin.cs | 12 +- SharedLibrary/Commands/NativeCommands.cs | 49 +-- SharedLibrary/Event.cs | 16 +- SharedLibrary/File.cs | 74 +--- SharedLibrary/Interfaces/IManager.cs | 1 + SharedLibrary/Player.cs | 9 +- SharedLibrary/RCON.cs | 2 +- SharedLibrary/Server.cs | 65 +-- SharedLibrary/WebService.cs | 44 +-- 22 files changed, 507 insertions(+), 573 deletions(-) rename Admin/{Config.cs => ServerConfig.cs} (89%) create mode 100644 Plugins/SimpleStats/Fakes/System.Data.SQLite.fakes diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj index eb618931e..3251bc472 100644 --- a/Admin/IW4M ADMIN.csproj +++ b/Admin/IW4M ADMIN.csproj @@ -123,7 +123,7 @@ - + diff --git a/Admin/Kayak.cs b/Admin/Kayak.cs index d0896e408..432b9d91d 100644 --- a/Admin/Kayak.cs +++ b/Admin/Kayak.cs @@ -13,6 +13,11 @@ namespace IW4MAdmin { public void OnException(IScheduler scheduler, Exception e) { + // it looks like there's a library error in + // Kayak.Http.HttpServerTransactionDelegate.OnError + if (e.GetType() == typeof(NullReferenceException)) + return; + Manager.GetInstance().Logger.WriteWarning("Web service has encountered an error - " + e.Message); Manager.GetInstance().Logger.WriteDebug($"Stack Trace: {e.StackTrace}"); @@ -26,7 +31,7 @@ namespace IW4MAdmin public void OnStop(IScheduler scheduler) { - Manager.GetInstance().Logger.WriteDebug("Web service has been stopped..."); + Manager.GetInstance().Logger.WriteInfo("Web service has been stopped..."); } } diff --git a/Admin/Logger.cs b/Admin/Logger.cs index 61aaed2a3..d31c3020c 100644 --- a/Admin/Logger.cs +++ b/Admin/Logger.cs @@ -40,8 +40,8 @@ namespace IW4MAdmin Console.WriteLine(LogLine); File.AppendAllText(FileName, LogLine + Environment.NewLine); #else - //if (type == LogType.Error || type == LogType.Verbose) - Console.WriteLine(LogLine); + if (type == LogType.Error || type == LogType.Verbose) + Console.WriteLine(LogLine); //if (type != LogType.Debug) File.AppendAllText(FileName, LogLine + Environment.NewLine); #endif diff --git a/Admin/Main.cs b/Admin/Main.cs index cc4b3ee23..379dbcca9 100644 --- a/Admin/Main.cs +++ b/Admin/Main.cs @@ -44,6 +44,7 @@ namespace IW4MAdmin do { userInput = Console.ReadLine(); + if (userInput.ToLower() == "quit") ServerManager.Stop(); @@ -55,7 +56,7 @@ namespace IW4MAdmin ServerManager.Servers[0].ExecuteEvent(E); Console.Write('>'); - } while (userInput != null && ServerManager.Running); + } while (ServerManager.Running); }); } diff --git a/Admin/Manager.cs b/Admin/Manager.cs index 2bbb95074..1641f4513 100644 --- a/Admin/Manager.cs +++ b/Admin/Manager.cs @@ -66,14 +66,14 @@ namespace IW4MAdmin var Configs = Directory.EnumerateFiles("config/servers").Where(x => x.Contains(".cfg")); if (Configs.Count() == 0) - Config.Generate(); + ServerConfig.Generate(); SharedLibrary.WebService.Init(); PluginImporter.Load(); foreach (var file in Configs) { - var Conf = Config.Read(file); + var Conf = ServerConfig.Read(file); var ServerInstance = new IW4MServer(this, Conf.IP, Conf.Port, Conf.Password); Task.Run(async () => @@ -125,7 +125,7 @@ namespace IW4MAdmin { Status.Update(new Task(() => (Status.Dependant as Server).ProcessUpdatesAsync(Status.GetToken()))); if (Status.RunAverage > 500) - Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).getIP()}::{(Status.Dependant as Server).getPort()} [{Status.RunAverage}ms]"); + Logger.WriteWarning($"Update task average execution is longer than desired for {(Status.Dependant as Server).GetIP()}::{(Status.Dependant as Server).GetPort()} [{Status.RunAverage}ms]"); } } @@ -170,5 +170,15 @@ namespace IW4MAdmin { return MessageTokens; } + + public IList GetActiveClients() + { + var ActiveClients = new List(); + + foreach (var server in Servers) + ActiveClients.AddRange(server.Players.Where(p => p != null)); + + return ActiveClients; + } } } diff --git a/Admin/Server.cs b/Admin/Server.cs index 10e5586e6..a9d2ce600 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -13,7 +13,7 @@ namespace IW4MAdmin { public IW4MServer(SharedLibrary.Interfaces.IManager mgr, string address, int port, string password) : base(mgr, address, port, password) { - initCommands(); + InitializeCommands(); } private void GetAliases(List returnAliases, Aliases currentAlias) @@ -85,7 +85,7 @@ namespace IW4MAdmin } // below this needs to be optimized ~ 425ms runtime - NewPlayer.updateName(P.Name.Trim()); + NewPlayer.UpdateName(P.Name.Trim()); NewPlayer.Alias = Manager.GetAliasesDatabase().GetPlayerAliases(NewPlayer.DatabaseID); if (NewPlayer.Alias == null) @@ -102,7 +102,7 @@ namespace IW4MAdmin // lets check aliases if ((NewPlayer.Alias.Names.Find(m => m.Equals(P.Name))) == null || NewPlayer.Name == null || NewPlayer.Name == String.Empty) { - NewPlayer.updateName(P.Name.Trim()); + NewPlayer.UpdateName(P.Name.Trim()); NewPlayer.Alias.Names.Add(NewPlayer.Name); } @@ -112,7 +112,7 @@ namespace IW4MAdmin NewPlayer.Alias.IPS.Add(P.IP); } - NewPlayer.updateIP(P.IP); + NewPlayer.SetIP(P.IP); Manager.GetAliasesDatabase().UpdatePlayerAliases(NewPlayer.Alias); Manager.GetClientDatabase().UpdatePlayer(NewPlayer); @@ -127,7 +127,7 @@ namespace IW4MAdmin return true; } - List newPlayerAliases = getPlayerAliases(NewPlayer); + List newPlayerAliases = GetPlayerAliases(NewPlayer); foreach (Player aP in newPlayerAliases) // lets check their aliases { @@ -135,7 +135,7 @@ namespace IW4MAdmin continue; if (aP.Level == Player.Permission.Flagged) - NewPlayer.setLevel(Player.Permission.Flagged); + NewPlayer.SetLevel(Player.Permission.Flagged); Penalty B = IsBanned(aP); @@ -398,9 +398,9 @@ namespace IW4MAdmin if ((lastCount - playerCountStart).TotalMinutes > 4) { - while (playerHistory.Count > 144) // 12 times a minute for 12 hours - playerHistory.Dequeue(); - playerHistory.Enqueue(new PlayerHistory(lastCount, ClientNum)); + while (PlayerHistory.Count > 144) // 12 times a minute for 12 hours + PlayerHistory.Dequeue(); + PlayerHistory.Enqueue(new PlayerHistory(lastCount, ClientNum)); playerCountStart = DateTime.Now; } @@ -415,13 +415,13 @@ namespace IW4MAdmin } //logFile = new IFile(); - if (l_size != logFile.getSize()) + if (l_size != logFile.Length()) { // this should be the longest running task await Task.FromResult(lines = logFile.Tail(12)); if (lines != oldLines) { - l_size = logFile.getSize(); + l_size = logFile.Length(); int end; if (lines.Length == oldLines.Length) end = lines.Length - 1; @@ -458,7 +458,7 @@ namespace IW4MAdmin } } oldLines = lines; - l_size = logFile.getSize(); + l_size = logFile.Length(); } #if DEBUG == false catch (SharedLibrary.Exceptions.NetworkException) @@ -486,6 +486,7 @@ namespace IW4MAdmin var game = await this.GetDvarAsync("fs_game"); var logfile = await this.GetDvarAsync("g_log"); var logsync = await this.GetDvarAsync("g_logsync"); + var onelog = await this.GetDvarAsync("iw4x_onelog"); try { @@ -512,22 +513,21 @@ namespace IW4MAdmin // this DVAR isn't set until the a map is loaded await this.SetDvarAsync("g_logsync", 1); await this.SetDvarAsync("g_log", "logs/games_mp.log"); + Logger.WriteWarning("Game log file not properly initialized, restarting map..."); await this.ExecuteCommandAsync("map_restart"); logfile = await this.GetDvarAsync("g_log"); } #if DEBUG basepath.Value = @"\\tsclient\K\MW2"; #endif - string logPath = string.Empty; - - if (game.Value == "") - logPath = $"{basepath.Value.Replace("\\", "/")}/userraw/{logfile.Value}"; - else - logPath = $"{basepath.Value.Replace("\\", "/")}/{game.Value}/{logfile.Value}"; + string logPath = (game.Value == "" || onelog.Value == 1) ? $"{basepath.Value.Replace("\\", "/")}/userraw/{logfile.Value}" : $"{basepath.Value.Replace("\\", "/")}/{game.Value}/{logfile.Value}"; if (!File.Exists(logPath)) { Logger.WriteError($"Gamelog {logPath} does not exist!"); +#if !DEBUG + throw new SharedLibrary.Exceptions.ServerException($"Invalid gamelog file {logPath}"); +#endif } logFile = new IFile(logPath); @@ -565,22 +565,11 @@ namespace IW4MAdmin if (E.Type == Event.GType.Kill) { - if (E.Origin == null) - { - Logger.WriteError("Kill event triggered, but no origin found!"); - return; - } - if (E.Origin != E.Target) - { await ExecuteEvent(new Event(Event.GType.Death, E.Data, E.Target, null, this)); - } else // suicide/falling - { - Logger.WriteDebug(E.Origin.Name + " suicided..."); await ExecuteEvent(new Event(Event.GType.Death, "suicide", E.Target, null, this)); - } } if (E.Type == Event.GType.Say) @@ -730,7 +719,7 @@ namespace IW4MAdmin if (Origin != null) { - Target.setLevel(Player.Permission.Banned); + Target.SetLevel(Player.Permission.Banned); Penalty newBan = new Penalty(Penalty.Type.Ban, Target.lastOffense, Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP); await Task.Run(() => @@ -771,20 +760,18 @@ namespace IW4MAdmin Manager.GetClientPenalties().RemovePenalty(PenaltyToRemove); Player P = Manager.GetClientDatabase().GetPlayer(Target.NetworkID, -1); - P.setLevel(Player.Permission.User); + P.SetLevel(Player.Permission.User); Manager.GetClientDatabase().UpdatePlayer(P); }); - } - public override bool Reload() { try { - initMaps(); - initMessages(); - initRules(); + InitializeMaps(); + InitializeAutoMessages(); + InitializeRules(); return true; } catch (Exception E) @@ -797,19 +784,18 @@ namespace IW4MAdmin } } - override public void initMacros() + override public void InitializeTokens() { Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYERS", Manager.GetClientDatabase().TotalPlayers().ToString)); Manager.GetMessageTokens().Add(new MessageToken("VERSION", Program.Version.ToString)); } - override public void initCommands() + override public void InitializeCommands() { foreach (Command C in PluginImporter.potentialCommands) Manager.GetCommands().Add(C); Manager.GetCommands().Add(new Plugins("plugins", "view all loaded plugins. syntax: !plugins", "p", Player.Permission.Administrator, 0, false)); - } } } diff --git a/Admin/Config.cs b/Admin/ServerConfig.cs similarity index 89% rename from Admin/Config.cs rename to Admin/ServerConfig.cs index 4c1cc714f..31070fdc4 100644 --- a/Admin/Config.cs +++ b/Admin/ServerConfig.cs @@ -9,7 +9,7 @@ using SharedLibrary.Interfaces; namespace IW4MAdmin { - public class Config : Serialize + public class ServerConfig : Serialize { public string IP; public int Port; @@ -21,7 +21,7 @@ namespace IW4MAdmin return $"config/servers/{IP}_{Port}.cfg"; } - public static Config Generate() + public static ServerConfig Generate() { string IP = String.Empty; int Port = 0; @@ -60,7 +60,7 @@ namespace IW4MAdmin Console.Write("Enter server RCON password: "); Password = Console.ReadLine(); - var config = new Config() { IP = IP, Password = Password, Port = Port }; + var config = new ServerConfig() { IP = IP, Password = Password, Port = Port }; config.Write(); Console.WriteLine("Config saved, add another? [y/n]:"); diff --git a/Admin/WebService.cs b/Admin/WebService.cs index 9df691966..4acddff24 100644 --- a/Admin/WebService.cs +++ b/Admin/WebService.cs @@ -19,19 +19,21 @@ namespace IW4MAdmin var webScheduler = Kayak.KayakScheduler.Factory.Create(new Scheduler()); webService = KayakServer.Factory.CreateHttp(new Request(), webScheduler); - SharedLibrary.WebService.pageList.Add(new Pages()); - SharedLibrary.WebService.pageList.Add(new Homepage()); - SharedLibrary.WebService.pageList.Add(new ServersJSON()); - SharedLibrary.WebService.pageList.Add(new Penalties()); - SharedLibrary.WebService.pageList.Add(new PenaltiesJSON()); - SharedLibrary.WebService.pageList.Add(new Players()); - SharedLibrary.WebService.pageList.Add(new GetPlayer()); - SharedLibrary.WebService.pageList.Add(new WebConsole()); - SharedLibrary.WebService.pageList.Add(new ConsoleJSON()); - SharedLibrary.WebService.pageList.Add(new PubbansJSON()); + SharedLibrary.WebService.PageList.Add(new Pages()); + SharedLibrary.WebService.PageList.Add(new Homepage()); + SharedLibrary.WebService.PageList.Add(new ServersJSON()); + SharedLibrary.WebService.PageList.Add(new Penalties()); + SharedLibrary.WebService.PageList.Add(new PenaltiesJSON()); + SharedLibrary.WebService.PageList.Add(new Players()); + SharedLibrary.WebService.PageList.Add(new GetPlayer()); + SharedLibrary.WebService.PageList.Add(new WebConsole()); + SharedLibrary.WebService.PageList.Add(new ConsoleJSON()); + SharedLibrary.WebService.PageList.Add(new PubbansJSON()); - Thread scheduleThread = new Thread(() => { ScheduleThreadStart(webScheduler, webService); }); - scheduleThread.Name = "Web Service Thread"; + Thread scheduleThread = new Thread(() => { ScheduleThreadStart(webScheduler, webService); }) + { + Name = "Web Service Thread" + }; scheduleThread.Start(); return webScheduler; @@ -66,16 +68,16 @@ namespace IW4MAdmin public static HttpResponse GetPage(string path, System.Collections.Specialized.NameValueCollection queryset, IDictionary headers) { - if (SharedLibrary.WebService.pageList == null || SharedLibrary.WebService.pageList.Count == 0) + if (SharedLibrary.WebService.PageList == null || SharedLibrary.WebService.PageList.Count == 0) return new HttpResponse() { content = "Error: page list not initialized!", contentType = "text/plaintext" }; if (path == null) return new HttpResponse() { content = "Error: no path specified", contentType = "text/plaintext" }; - IPage requestedPage = SharedLibrary.WebService.pageList.Find(x => x.getPath().ToLower() == path.ToLower()); + IPage requestedPage = SharedLibrary.WebService.PageList.Find(x => x.GetPath().ToLower() == path.ToLower()); if (requestedPage != null) - return requestedPage.getPage(queryset, headers); + return requestedPage.GetPage(queryset, headers); else { if (System.IO.File.Exists(path.Replace("/", "\\").Substring(1))) @@ -85,10 +87,12 @@ namespace IW4MAdmin if (path.Contains(".css")) { - HttpResponse css = new HttpResponse(); - css.additionalHeaders = new Dictionary(); - css.content = f.getLines(); - css.contentType = "text/css"; + HttpResponse css = new HttpResponse() + { + additionalHeaders = new Dictionary(), + content = f.GetText(), + contentType = "text/css" + }; f.Close(); return css; @@ -96,10 +100,12 @@ namespace IW4MAdmin else if (path.Contains(".js")) { - HttpResponse css = new HttpResponse(); - css.additionalHeaders = new Dictionary(); - css.content = f.getLines(); - css.contentType = "application/javascript"; + HttpResponse css = new HttpResponse() + { + additionalHeaders = new Dictionary(), + content = f.GetText(), + contentType = "application/javascript" + }; f.Close(); return css; } @@ -108,39 +114,40 @@ namespace IW4MAdmin } requestedPage = new Error404(); - return requestedPage.getPage(queryset, headers); + return requestedPage.GetPage(queryset, headers); } } } class Error404 : IPage { - public string getName() + public string GetName() { return "404"; } - public string getPath() + public string GetPath() { return ""; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { - HttpResponse resp = new HttpResponse(); - resp.additionalHeaders = new Dictionary(); - resp.content = "404 not found!"; - resp.contentType = getContentType(); - + HttpResponse resp = new HttpResponse() + { + additionalHeaders = new Dictionary(), + content = "404 not found!", + contentType = GetContentType() + }; return resp; } - public string getContentType() + public string GetContentType() { return "text/html"; } - public bool isVisible() + public bool Visible() { return false; } @@ -148,24 +155,24 @@ namespace IW4MAdmin class Homepage : HTMLPage { - public override string getName() + public override string GetName() { return "Home"; } - public override string getPath() + public override string GetPath() { return "/"; } - public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public override string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { StringBuilder S = new StringBuilder(); - S.Append(loadHeader()); + S.Append(LoadHeader()); IFile p = new IFile("webfront\\main.html"); - S.Append(p.getLines()); + S.Append(p.GetText()); p.Close(); - S.Append(loadFooter()); + S.Append(LoadFooter()); return S.ToString(); } @@ -173,37 +180,42 @@ namespace IW4MAdmin class ServersJSON : IPage { - public string getName() + public string GetName() { return "Servers"; } - public string getPath() + public string GetPath() { return "/_servers"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { var info = new List(); foreach (Server S in Manager.GetInstance().Servers) { - ServerInfo eachServer = new ServerInfo(); - eachServer.serverName = S.getName(); - eachServer.serverPort = S.getPort(); - eachServer.maxPlayers = S.MaxClients; - eachServer.mapName = S.CurrentMap.Alias; - eachServer.gameType = Utilities.gametypeLocalized(S.getGametype()); - eachServer.currentPlayers = S.GetPlayersAsList().Count; - eachServer.chatHistory = S.ChatHistory; - eachServer.players = new List(); + ServerInfo eachServer = new ServerInfo() + { + serverName = S.Hostname, + serverPort = S.GetPort(), + maxPlayers = S.MaxClients, + mapName = S.CurrentMap.Alias, + gameType = Utilities.gametypeLocalized(S.Gametype), + currentPlayers = S.GetPlayersAsList().Count, + chatHistory = S.ChatHistory, + players = new List() + }; + foreach (Player P in S.GetPlayersAsList()) { - PlayerInfo pInfo = new PlayerInfo(); - pInfo.playerID = P.DatabaseID; - pInfo.playerName = P.Name; - pInfo.playerLevel = P.Level.ToString(); + PlayerInfo pInfo = new PlayerInfo() + { + playerID = P.DatabaseID, + playerName = P.Name, + playerLevel = P.Level.ToString() + }; eachServer.players.Add(pInfo); } @@ -211,19 +223,21 @@ namespace IW4MAdmin } - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info); - resp.additionalHeaders = new Dictionary(); + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(info), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -231,35 +245,38 @@ namespace IW4MAdmin class Info : IPage { - public string getName() + public string GetName() { return "Info"; } - public string getPath() + public string GetPath() { return "/_info"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { - ApplicationInfo info = new ApplicationInfo(); - info.name = "IW4MAdmin"; - info.version = Program.Version; - - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info); - resp.additionalHeaders = new Dictionary(); + ApplicationInfo info = new ApplicationInfo() + { + name = "IW4MAdmin", + version = Program.Version + }; + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(info), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -268,27 +285,29 @@ namespace IW4MAdmin class ConsoleJSON : IPage { - public string getName() + public string GetName() { return "_Console"; } - public string getPath() + public string GetPath() { return "/_console"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { - CommandInfo cmd = new CommandInfo(); - cmd.Result = new List(); + CommandInfo cmd = new CommandInfo() + { + Result = new List() + }; if (querySet["command"] != null) { if (querySet["server"] != null) { - Server S = Manager.GetInstance().Servers.ToList().Find(x => (x.getPort().ToString() == querySet["server"])); + Server S = Manager.GetInstance().Servers.ToList().Find(x => (x.GetPort().ToString() == querySet["server"])); if (S != null) { @@ -297,8 +316,10 @@ namespace IW4MAdmin if (admin == null) admin = new Player("RestUser", "-1", -1, (int)Player.Permission.User); - Event remoteEvent = new Event(Event.GType.Say, querySet["command"], admin, null, S); - remoteEvent.Remote = true; + Event remoteEvent = new Event(Event.GType.Say, querySet["command"], admin, null, S) + { + Remote = true + }; admin.lastEvent = remoteEvent; S.ExecuteEvent(remoteEvent); @@ -318,19 +339,21 @@ namespace IW4MAdmin cmd.Result.Add("No command entered."); } - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(cmd); - resp.additionalHeaders = new Dictionary(); + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(cmd), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -339,17 +362,17 @@ namespace IW4MAdmin class PenaltiesJSON : IPage { - public string getName() + public string GetName() { return "Penalties"; } - public string getPath() + public string GetPath() { return "/_penalties"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { int from = 0; if (querySet["from"] != null) @@ -377,14 +400,18 @@ namespace IW4MAdmin continue; if (admin == null) admin = new Player("Unknown", "-1", -1, (int)Player.Permission.Banned); - PenaltyInfo pInfo = new PenaltyInfo(); - pInfo.adminName = admin.Name; - pInfo.adminLevel = admin.Level.ToString(); - pInfo.penaltyReason = p.Reason; - pInfo.penaltyTime = SharedLibrary.Utilities.timePassed(p.When); - pInfo.penaltyType = p.BType.ToString(); - pInfo.playerName = penalized.Name; - pInfo.playerID = penalized.DatabaseID; + + PenaltyInfo pInfo = new PenaltyInfo() + { + adminName = admin.Name, + adminLevel = admin.Level.ToString(), + penaltyReason = p.Reason, + penaltyTime = SharedLibrary.Utilities.timePassed(p.When), + penaltyType = p.BType.ToString(), + playerName = penalized.Name, + playerID = penalized.DatabaseID + }; + if (admin.NetworkID == penalized.NetworkID) { pInfo.adminName = "IW4MAdmin"; @@ -393,19 +420,21 @@ namespace IW4MAdmin info.Add(pInfo); } - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(info); - resp.additionalHeaders = new Dictionary(); + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(info), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -413,26 +442,26 @@ namespace IW4MAdmin class Penalties : HTMLPage { - public override string getName() + public override string GetName() { return "Penalties"; } - public override string getPath() + public override string GetPath() { return "/penalties"; } - public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public override string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { StringBuilder S = new StringBuilder(); - S.Append(loadHeader()); + S.Append(LoadHeader()); IFile penalities = new IFile("webfront\\penalties.html"); - S.Append(penalities.getLines()); + S.Append(penalities.GetText()); penalities.Close(); - S.Append(loadFooter()); + S.Append(LoadFooter()); return S.ToString(); } @@ -440,26 +469,26 @@ namespace IW4MAdmin class WebConsole : HTMLPage { - public override string getName() + public override string GetName() { return "Console"; } - public override string getPath() + public override string GetPath() { return "/console"; } - public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public override string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { StringBuilder S = new StringBuilder(); - S.Append(loadHeader()); + S.Append(LoadHeader()); IFile console = new IFile("webfront\\console.html"); - S.Append(console.getLines()); + S.Append(console.GetText()); console.Close(); - S.Append(loadFooter()); + S.Append(LoadFooter()); return S.ToString(); } @@ -467,26 +496,26 @@ namespace IW4MAdmin class Players : HTMLPage { - public override string getName() + public override string GetName() { return "Players"; } - public override string getPath() + public override string GetPath() { return "/players"; } - public override string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public override string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { StringBuilder S = new StringBuilder(); - S.Append(loadHeader()); + S.Append(LoadHeader()); IFile penalities = new IFile("webfront\\players.html"); - S.Append(penalities.getLines()); + S.Append(penalities.GetText()); penalities.Close(); - S.Append(loadFooter()); + S.Append(LoadFooter()); return S.ToString(); } @@ -494,31 +523,33 @@ namespace IW4MAdmin class PubbansJSON : IPage { - public string getName() + public string GetName() { return "Public Ban List"; } - public string getPath() + public string GetPath() { return "/pubbans"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(((Manager.GetInstance().GetClientPenalties()) as PenaltyList).AsChronoList(Convert.ToInt32(querySet["from"]), 15), Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonConverter[] { new Newtonsoft.Json.Converters.StringEnumConverter() }); - resp.additionalHeaders = new Dictionary(); + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(((Manager.GetInstance().GetClientPenalties()) as PenaltyList).AsChronoList(Convert.ToInt32(querySet["from"]), 15), Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonConverter[] { new Newtonsoft.Json.Converters.StringEnumConverter() }), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -526,46 +557,49 @@ namespace IW4MAdmin class Pages : IPage { - public string getName() + public string GetName() { return "Pages"; } - public string getPath() + public string GetPath() { return "/pages"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { List pages = new List(); - foreach (var p in SharedLibrary.WebService.pageList.Where(x => x.isVisible())) + foreach (var p in SharedLibrary.WebService.PageList.Where(x => x.Visible())) { if (p == this) continue; - PageInfo pi = new PageInfo(); - pi.pagePath = p.getPath(); - // pi.pageType = p.getPage(querySet, headers).contentType; - pi.pageName = p.getName(); - pi.visible = p.isVisible(); + PageInfo pi = new PageInfo() + { + pagePath = p.GetPath(), + pageName = p.GetName(), + visible = p.Visible() + }; pages.Add(pi); } - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(pages); - resp.additionalHeaders = new Dictionary(); + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(pages), + additionalHeaders = new Dictionary() + }; return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -573,29 +607,30 @@ namespace IW4MAdmin class GetPlayer : IPage { - public string getContentType() + public string GetContentType() { return "application/json"; } - public string getPath() + public string GetPath() { return "/getplayer"; } - public string getName() + public string GetName() { return "GetPlayer"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { List pInfo = new List(); List matchedPlayers = new List(); - HttpResponse resp = new HttpResponse(); - resp.contentType = getContentType(); - resp.additionalHeaders = new Dictionary(); - + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + additionalHeaders = new Dictionary() + }; bool authed = Manager.GetInstance().GetClientDatabase().GetAdmins().FindAll(x => x.IP == querySet["IP"]).Count > 0; bool recent = false; @@ -625,15 +660,18 @@ namespace IW4MAdmin foreach (var pp in matchedPlayers) { if (pp == null) continue; - PlayerInfo eachPlayer = new PlayerInfo(); - eachPlayer.playerID = pp.DatabaseID; - eachPlayer.playerIP = pp.IP; - eachPlayer.playerLevel = pp.Level.ToString(); - eachPlayer.playerName = pp.Name; - eachPlayer.playernpID = pp.NetworkID; - eachPlayer.forumID = -1; - eachPlayer.authed = authed; - eachPlayer.showV2Features = false; + + PlayerInfo eachPlayer = new PlayerInfo() + { + playerID = pp.DatabaseID, + playerIP = pp.IP, + playerLevel = pp.Level.ToString(), + playerName = pp.Name, + playernpID = pp.NetworkID, + forumID = -1, + authed = authed, + showV2Features = false + }; if (!recent) { @@ -658,7 +696,7 @@ namespace IW4MAdmin return resp; } - public bool isVisible() + public bool Visible() { return false; } diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll index f897e40a5564c5ea607a2443e3609d6e6c724a75..ad3b75cee96ca92afb229c2a49f3c61474b2b45c 100644 GIT binary patch literal 102912 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 literal 97280 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 ESBPqa*8l(j diff --git a/Plugins/EventAPI/Plugin.cs b/Plugins/EventAPI/Plugin.cs index 190bfa00a..aa76d99a9 100644 --- a/Plugins/EventAPI/Plugin.cs +++ b/Plugins/EventAPI/Plugin.cs @@ -15,17 +15,17 @@ namespace EventAPI public RestEvent Event; } - public string getName() + public string GetName() { return "Events"; } - public string getPath() + public string GetPath() { return "/api/events"; } - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { bool shouldQuery = querySet.Get("status") != null; EventResponse requestedEvent = new EventResponse(); @@ -34,15 +34,15 @@ namespace EventAPI if (shouldQuery) { StringBuilder s = new StringBuilder(); - foreach (var S in Events.activeServers) - s.Append(String.Format("{0} has {1}/{4} players playing {2} on {3}\n", S.getName(), S.GetPlayersAsList().Count, Utilities.gametypeLocalized(S.getGametype()), S.CurrentMap.Name, S.MaxClients)); - requestedEvent.Event = new RestEvent(RestEvent.eType.STATUS, RestEvent.eVersion.IW4MAdmin, s.ToString(), "Status", "", ""); + foreach (var S in Events.ActiveServers) + s.Append(String.Format("{0} has {1}/{4} players playing {2} on {3}\n", S.Hostname, S.GetPlayersAsList().Count, Utilities.gametypeLocalized(S.Gametype), S.CurrentMap.Name, S.MaxClients)); + requestedEvent.Event = new RestEvent(RestEvent.EventType.STATUS, RestEvent.EventVersion.IW4MAdmin, s.ToString(), "Status", "", ""); requestedEvent.eventCount = 1; } - else if (Events.apiEvents.Count > 0) + else if (Events.APIEvents.Count > 0) { - requestedEvent.Event = Events.apiEvents.Dequeue(); + requestedEvent.Event = Events.APIEvents.Dequeue(); requestedEvent.eventCount = 1; } @@ -52,17 +52,17 @@ namespace EventAPI } resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedEvent); - resp.contentType = getContentType(); + resp.contentType = GetContentType(); resp.additionalHeaders = new Dictionary(); return resp; } - public string getContentType() + public string GetContentType() { return "application/json"; } - public bool isVisible() + public bool Visible() { return false; } @@ -70,8 +70,8 @@ namespace EventAPI class Events : IPlugin { - public static Queue apiEvents { get; private set; } - public static List activeServers; + public static Queue APIEvents { get; private set; } + public static List ActiveServers; DateTime lastClear; int flaggedMessages; @@ -97,16 +97,16 @@ namespace EventAPI public async Task OnLoadAsync() { - apiEvents = new Queue(); + APIEvents = new Queue(); flaggedMessagesText = new List(); - activeServers = new List(); - WebService.pageList.Add(new EventsJSON()); + ActiveServers = new List(); + WebService.PageList.Add(new EventsJSON()); } public async Task OnUnloadAsync() { - apiEvents.Clear(); - activeServers.Clear(); + APIEvents.Clear(); + ActiveServers.Clear(); } public async Task OnTickAsync(Server S) @@ -118,29 +118,29 @@ namespace EventAPI { if (E.Type == Event.GType.Start) { - activeServers.Add(S); + ActiveServers.Add(S); } if (E.Type == Event.GType.Stop) { // fixme: this will be bad once FTP is working and there can be multiple servers on the same port. - activeServers.RemoveAll(s => s.getPort() == S.getPort()); + ActiveServers.RemoveAll(s => s.GetPort() == S.GetPort()); } if (E.Type == Event.GType.Connect) { - addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Origin.Name + " has joined " + S.getName(), E.Type.ToString(), S.getName(), E.Origin.Name)); + AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, E.Origin.Name + " has joined " + S.Hostname, E.Type.ToString(), S.Hostname, E.Origin.Name)); } if (E.Type == Event.GType.Disconnect) { - addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Origin.Name + " has left " + S.getName(), E.Type.ToString(), S.getName(), E.Origin.Name)); + AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, E.Origin.Name + " has left " + S.Hostname, E.Type.ToString(), S.Hostname, E.Origin.Name)); } if (E.Type == Event.GType.Say) { if (E.Data.Length != 0 && E.Data[0] != '!') - addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, E.Data, "Chat", E.Origin.Name, "")); + AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, E.Data, "Chat", E.Origin.Name, "")); } if (E.Type == Event.GType.Say && E.Origin.Level < Player.Permission.Moderator) @@ -158,8 +158,8 @@ namespace EventAPI { await E.Owner.Broadcast("If you suspect someone of ^5CHEATING ^7use the ^5!report ^7command"); - addRestEvent(new RestEvent(RestEvent.eType.ALERT, RestEvent.eVersion.IW4MAdmin, "Chat indicates there may be a cheater", "Alert", E.Owner.getName(), "")); - addRestEvent(new RestEvent(RestEvent.eType.NOTIFICATION, RestEvent.eVersion.IW4MAdmin, String.Join("\n", flaggedMessagesText), "Chat Monitor", E.Owner.getName(), "")); + AddRestEvent(new RestEvent(RestEvent.EventType.ALERT, RestEvent.EventVersion.IW4MAdmin, "Chat indicates there may be a cheater", "Alert", E.Owner.Hostname, "")); + AddRestEvent(new RestEvent(RestEvent.EventType.NOTIFICATION, RestEvent.EventVersion.IW4MAdmin, String.Join("\n", flaggedMessagesText), "Chat Monitor", E.Owner.Hostname, "")); flaggedMessages = 0; } @@ -172,11 +172,11 @@ namespace EventAPI } } - public static void addRestEvent(RestEvent E) + public static void AddRestEvent(RestEvent E) { - if (apiEvents.Count > 10) - apiEvents.Dequeue(); - apiEvents.Enqueue(E); + if (APIEvents.Count > 10) + APIEvents.Dequeue(); + APIEvents.Enqueue(E); } } } diff --git a/Plugins/MessageBoard/Forum.cs b/Plugins/MessageBoard/Forum.cs index 416d39b5e..fd49b6aad 100644 --- a/Plugins/MessageBoard/Forum.cs +++ b/Plugins/MessageBoard/Forum.cs @@ -343,26 +343,26 @@ namespace MessageBoard.Forum forumPages.Add(logout); forumPages.Add(stats); - SharedLibrary.WebService.pageList.Add(login); - SharedLibrary.WebService.pageList.Add(loginJSON); - SharedLibrary.WebService.pageList.Add(register); - SharedLibrary.WebService.pageList.Add(registerJSON); - SharedLibrary.WebService.pageList.Add(userinfoJSON); - SharedLibrary.WebService.pageList.Add(viewUser); - SharedLibrary.WebService.pageList.Add(userCP); - SharedLibrary.WebService.pageList.Add(updateUserJSON); - SharedLibrary.WebService.pageList.Add(categoriesJSON); - SharedLibrary.WebService.pageList.Add(category); - SharedLibrary.WebService.pageList.Add(categorythreadsJSON); - SharedLibrary.WebService.pageList.Add(home); - SharedLibrary.WebService.pageList.Add(recentthreadsJSON); - SharedLibrary.WebService.pageList.Add(postthread); - SharedLibrary.WebService.pageList.Add(postthreadJSON); - SharedLibrary.WebService.pageList.Add(editthreadJSON); - SharedLibrary.WebService.pageList.Add(threadJSON); - SharedLibrary.WebService.pageList.Add(viewthread); - SharedLibrary.WebService.pageList.Add(logout); - SharedLibrary.WebService.pageList.Add(stats); + SharedLibrary.WebService.PageList.Add(login); + SharedLibrary.WebService.PageList.Add(loginJSON); + SharedLibrary.WebService.PageList.Add(register); + SharedLibrary.WebService.PageList.Add(registerJSON); + SharedLibrary.WebService.PageList.Add(userinfoJSON); + SharedLibrary.WebService.PageList.Add(viewUser); + SharedLibrary.WebService.PageList.Add(userCP); + SharedLibrary.WebService.PageList.Add(updateUserJSON); + SharedLibrary.WebService.PageList.Add(categoriesJSON); + SharedLibrary.WebService.PageList.Add(category); + SharedLibrary.WebService.PageList.Add(categorythreadsJSON); + SharedLibrary.WebService.PageList.Add(home); + SharedLibrary.WebService.PageList.Add(recentthreadsJSON); + SharedLibrary.WebService.PageList.Add(postthread); + SharedLibrary.WebService.PageList.Add(postthreadJSON); + SharedLibrary.WebService.PageList.Add(editthreadJSON); + SharedLibrary.WebService.PageList.Add(threadJSON); + SharedLibrary.WebService.PageList.Add(viewthread); + SharedLibrary.WebService.PageList.Add(logout); + SharedLibrary.WebService.PageList.Add(stats); guestRank = database.getRank("Guest"); UserRank = database.getRank("User"); @@ -375,7 +375,7 @@ namespace MessageBoard.Forum //session logouts //checkme foreach (var page in forumPages) - SharedLibrary.WebService.pageList.Remove(page); + SharedLibrary.WebService.PageList.Remove(page); } } @@ -386,22 +386,22 @@ namespace MessageBoard.Forum { protected Session currentSession; - public bool isVisible() + public bool Visible() { return false; } - public virtual string getPath() + public virtual string GetPath() { return "/forum"; } - public string getName() + public string GetName() { return "JSONPage"; } - public virtual HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary requestHeaders) + public virtual HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary requestHeaders) { HttpResponse resp = new HttpResponse(); resp.contentType = "application/json"; @@ -431,22 +431,22 @@ namespace MessageBoard.Forum abstract public class ForumPage : HTMLPage { public ForumPage(bool visible) : base(visible) { } - public abstract override string getName(); - public override string getPath() + public abstract override string GetName(); + public override string GetPath() { - return base.getPath() + "/forum"; + return base.GetPath() + "/forum"; } - public override Dictionary getHeaders(IDictionary requestHeaders) + public override Dictionary GetHeaders(IDictionary requestHeaders) { - return base.getHeaders(requestHeaders); + return base.GetHeaders(requestHeaders); } protected string templatation(string bodyContent) { StringBuilder S = new StringBuilder(); - S.Append(base.loadHeader()); + S.Append(base.LoadHeader()); S.Append(bodyContent); - S.Append(base.loadFooter()); + S.Append(base.LoadFooter()); return S.ToString(); } @@ -459,19 +459,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/login"; + return base.GetPath() + "/login"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - return templatation(loadFile("forum\\login.html")); + return templatation(LoadFile("forum\\login.html")); } } @@ -482,19 +482,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Register"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/register"; + return base.GetPath() + "/register"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\register.html"); + string content = LoadFile("forum\\register.html"); return templatation(content); } } @@ -506,19 +506,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - Home"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/home"; + return base.GetPath() + "/home"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\home.html"); + string content = LoadFile("forum\\home.html"); return templatation(content); } } @@ -530,19 +530,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - Post New Thread"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/postthread"; + return base.GetPath() + "/postthread"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\postthread.html"); + string content = LoadFile("forum\\postthread.html"); return templatation(content); } } @@ -554,19 +554,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - Category View"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/category"; + return base.GetPath() + "/category"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\category.html"); + string content = LoadFile("forum\\category.html"); return templatation(content); } } @@ -578,19 +578,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - View User"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/user"; + return base.GetPath() + "/user"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\user.html"); + string content = LoadFile("forum\\user.html"); return templatation(content); } } @@ -602,19 +602,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - User Control Panel"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/usercp"; + return base.GetPath() + "/usercp"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\usercp.html"); + string content = LoadFile("forum\\usercp.html"); return templatation(content); } } @@ -626,19 +626,19 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - View Thread"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/thread"; + return base.GetPath() + "/thread"; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { - string content = loadFile("forum\\thread.html"); + string content = LoadFile("forum\\thread.html"); return templatation(content); } } @@ -650,23 +650,23 @@ namespace MessageBoard.Forum } - public override string getName() + public override string GetName() { return "Forum - Log Out"; } - public override string getPath() + public override string GetPath() { - return base.getPath() + "/logout"; + return base.GetPath() + "/logout"; } - public override Dictionary getHeaders(IDictionary requestHeaders) + public override Dictionary GetHeaders(IDictionary requestHeaders) { Plugin.Main.forum.removeSession(requestHeaders["Cookie"].Split('=')[1]); return new Dictionary() { { "Set-Cookie", "IW4MAdmin_ForumSession=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT" } }; } - public override string getContent(NameValueCollection querySet, IDictionary headers) + public override string GetContent(NameValueCollection querySet, IDictionary headers) { string content = @""; return templatation(content); @@ -675,18 +675,18 @@ namespace MessageBoard.Forum public class RegisterJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_register"; + return base.GetPath() + "/_register"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var result = new ActionResponse(); result.success = false; - result.destination = base.getPath() + "/error"; + result.destination = base.GetPath() + "/error"; try { @@ -723,7 +723,7 @@ namespace MessageBoard.Forum else { - result.destination = base.getPath() + "/home"; + result.destination = base.GetPath() + "/home"; result.success = true; result.errorCode = Manager.ErrorCode.NO_ERROR; } @@ -742,14 +742,14 @@ namespace MessageBoard.Forum public class userinfoJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_userinfo"; + return base.GetPath() + "/_userinfo"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); UserInfo info = new UserInfo(); bool validUserSelection = true; @@ -800,14 +800,14 @@ namespace MessageBoard.Forum public class updateUserJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_updateuser"; + return base.GetPath() + "/_updateuser"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var aResp = new ActionResponse(); bool passwordUpdateRequest = false; @@ -892,14 +892,14 @@ namespace MessageBoard.Forum public class LoginJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_login"; + return base.GetPath() + "/_login"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); ActionResponse aResp = new ActionResponse(); aResp.success = false; @@ -926,14 +926,14 @@ namespace MessageBoard.Forum public class categoriesJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_categories"; + return base.GetPath() + "/_categories"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var categories = Plugin.Main.forum.getAllCategories(); @@ -944,14 +944,14 @@ namespace MessageBoard.Forum public class recentthreadsJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_recentthreads"; + return base.GetPath() + "/_recentthreads"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); try { @@ -986,14 +986,14 @@ namespace MessageBoard.Forum public class categorythreadsJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_categorythreads"; + return base.GetPath() + "/_categorythreads"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var aResp = new ActionResponse(); try @@ -1033,14 +1033,14 @@ namespace MessageBoard.Forum public class threadJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_thread"; + return base.GetPath() + "/_thread"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var aResp = new ActionResponse(); aResp.success = false; aResp.errorCode = Manager.ErrorCode.NO_ERROR; @@ -1096,14 +1096,14 @@ namespace MessageBoard.Forum public class editthreadJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_editthread"; + return base.GetPath() + "/_editthread"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); var aResp = new ActionResponse(); aResp.success = false; aResp.errorCode = Manager.ErrorCode.NO_ERROR; @@ -1237,14 +1237,14 @@ namespace MessageBoard.Forum public class postthreadJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_postthread"; + return base.GetPath() + "/_postthread"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); ActionResponse aResp = new ActionResponse(); if (currentSession.sessionUser.ranking.equivalentRank < Player.Permission.Trusted) @@ -1316,14 +1316,14 @@ namespace MessageBoard.Forum public class StatsJSON : JSONPage { - public override string getPath() + public override string GetPath() { - return base.getPath() + "/_stats"; + return base.GetPath() + "/_stats"; } - public override HttpResponse getPage(NameValueCollection querySet, IDictionary requestHeaders) + public override HttpResponse GetPage(NameValueCollection querySet, IDictionary requestHeaders) { - var resp = base.getPage(querySet, requestHeaders); + var resp = base.GetPage(querySet, requestHeaders); StatView stats = new StatView(); stats.onlineUsers = new List(); diff --git a/Plugins/SimpleStats/Fakes/System.Data.SQLite.fakes b/Plugins/SimpleStats/Fakes/System.Data.SQLite.fakes new file mode 100644 index 0000000000000000000000000000000000000000..8cb05f45c4460b6880e3e0dd552358eb3ea65f32 GIT binary patch literal 252 zcmYL^O$x#=5QX1b@D3#hNUBST1wmYiAcFfU6^pi!rVG8i`lTXe7-r_>{gBVwYok&( zRf@{=RHM6E_N9!j>Zykoa#YkAq=HehTV@T?DR2c{U|Q|~?zsM*PIKj&Q4YsKQ%%Up ze G7Wx8{j47u8 literal 0 HcmV?d00001 diff --git a/Plugins/SimpleStats/Plugin.cs b/Plugins/SimpleStats/Plugin.cs index 472bde841..547656d63 100644 --- a/Plugins/SimpleStats/Plugin.cs +++ b/Plugins/SimpleStats/Plugin.cs @@ -26,13 +26,13 @@ namespace StatsPlugin if (E.Target != null) { - pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetStats(E.Target); + pStats = Stats.statLists.Find(x => x.Port == E.Owner.GetPort()).playerStats.GetStats(E.Target); statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill); } else { - pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetStats(E.Origin); + pStats = Stats.statLists.Find(x => x.Port == E.Owner.GetPort()).playerStats.GetStats(E.Origin); statLine = String.Format("^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Skill); } @@ -58,7 +58,7 @@ namespace StatsPlugin public override async Task ExecuteAsync(Event E) { - List> pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetTopStats(); + List> pStats = Stats.statLists.Find(x => x.Port == E.Owner.GetPort()).playerStats.GetTopStats(); StringBuilder msgBlder = new StringBuilder(); await E.Origin.Tell("^5--Top Players--"); @@ -79,13 +79,13 @@ namespace StatsPlugin public override async Task ExecuteAsync(Event E) { - var stats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetStats(E.Origin); + var stats = Stats.statLists.Find(x => x.Port == E.Owner.GetPort()).playerStats.GetStats(E.Origin); stats.Deaths = 0; stats.Kills = 0; stats.scorePerMinute = 1.0; stats.Skill = 1; stats.KDR = 0.0; - await Task.Run(() => { Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.UpdateStats(E.Origin, stats); }); + await Task.Run(() => { Stats.statLists.Find(x => x.Port == E.Owner.GetPort()).playerStats.UpdateStats(E.Origin, stats); }); await E.Origin.Tell("Your stats have been reset"); } } @@ -152,7 +152,7 @@ namespace StatsPlugin { if (E.Type == Event.GType.Start) { - statLists.Add(new StatTracking(S.getPort())); + statLists.Add(new StatTracking(S.GetPort())); if (statLists.Count == 1) { S.Manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", GetTotalKills)); @@ -162,17 +162,17 @@ namespace StatsPlugin if (E.Type == Event.GType.Stop) { - statLists.RemoveAll(x => x.Port == S.getPort()); + statLists.RemoveAll(x => x.Port == S.GetPort()); } if (E.Type == Event.GType.Connect) { - ResetCounters(E.Origin.ClientID, S.getPort()); + ResetCounters(E.Origin.ClientID, S.GetPort()); - PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.getPort()).playerStats.GetStats(E.Origin); + PlayerStats checkForTrusted = statLists.Find(x => x.Port == S.GetPort()).playerStats.GetStats(E.Origin); if (checkForTrusted.TotalPlayTime >= 4320 && E.Origin.Level < Player.Permission.Trusted) { - E.Origin.setLevel(Player.Permission.Trusted); + E.Origin.SetLevel(Player.Permission.Trusted); E.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Origin); await E.Origin.Tell("Congratulations, you are now a ^5trusted ^7player! Type ^5!help ^7to view new commands."); await E.Origin.Tell("You earned this by playing for ^53 ^7full days!"); @@ -187,8 +187,8 @@ namespace StatsPlugin if (P == null) continue; - CalculateAndSaveSkill(P, statLists.Find(x =>x.Port == S.getPort())); - ResetCounters(P.ClientID, S.getPort()); + CalculateAndSaveSkill(P, statLists.Find(x =>x.Port == S.GetPort())); + ResetCounters(P.ClientID, S.GetPort()); E.Owner.Logger.WriteInfo("Updated skill for client #" + P.DatabaseID); //E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.clientID].ToShortTimeString(), inactiveMinutes[P.clientID], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths)); @@ -197,8 +197,8 @@ namespace StatsPlugin if (E.Type == Event.GType.Disconnect) { - CalculateAndSaveSkill(E.Origin, statLists.Find(x=>x.Port == S.getPort())); - ResetCounters(E.Origin.ClientID, S.getPort()); + CalculateAndSaveSkill(E.Origin, statLists.Find(x=>x.Port == S.GetPort())); + ResetCounters(E.Origin.ClientID, S.GetPort()); E.Owner.Logger.WriteInfo("Updated skill for disconnecting client #" + E.Origin.DatabaseID); } @@ -208,7 +208,7 @@ namespace StatsPlugin return; Player Killer = E.Origin; - StatTracking curServer = statLists.Find(x => x.Port == S.getPort()); + StatTracking curServer = statLists.Find(x => x.Port == S.GetPort()); PlayerStats killerStats = curServer.playerStats.GetStats(Killer); @@ -237,7 +237,7 @@ namespace StatsPlugin return; Player Victim = E.Origin; - StatTracking curServer = statLists.Find(x => x.Port == S.getPort()); + StatTracking curServer = statLists.Find(x => x.Port == S.GetPort()); PlayerStats victimStats = curServer.playerStats.GetStats(Victim); victimStats.Deaths++; diff --git a/Plugins/VoteMap/Plugin.cs b/Plugins/VoteMap/Plugin.cs index df5a99e1c..e3c3ec209 100644 --- a/Plugins/VoteMap/Plugin.cs +++ b/Plugins/VoteMap/Plugin.cs @@ -27,7 +27,7 @@ namespace Votemap_Plugin /// This is the `say` event that comes from the server public override async Task ExecuteAsync(Event E) { - var voting = Vote.getServerVotes(E.Owner.getPort()); + var voting = Vote.getServerVotes(E.Owner.GetPort()); // we only want to allow a vote during a vote session if (voting.voteInSession) @@ -60,7 +60,7 @@ namespace Votemap_Plugin public override async Task ExecuteAsync(Event E) { - var voting = Vote.getServerVotes(E.Owner.getPort()); + var voting = Vote.getServerVotes(E.Owner.GetPort()); if (voting.voteInSession) { @@ -222,7 +222,7 @@ namespace Votemap_Plugin /// public async Task OnTickAsync(Server S) { - var serverVotes = getServerVotes(S.getPort()); + var serverVotes = getServerVotes(S.GetPort()); if (serverVotes != null) { @@ -282,17 +282,17 @@ namespace Votemap_Plugin { if (E.Type == Event.GType.Start) { - serverVotingList.Add(new ServerVoting(S.getPort())); + serverVotingList.Add(new ServerVoting(S.GetPort())); } if (E.Type == Event.GType.Stop) { - serverVotingList.RemoveAll(x => x.serverID == S.getPort()); + serverVotingList.RemoveAll(x => x.serverID == S.GetPort()); } if (E.Type == Event.GType.MapEnd || E.Type == Event.GType.MapChange) { - var serverVotes = getServerVotes(S.getPort()); + var serverVotes = getServerVotes(S.GetPort()); serverVotes.voteList.Clear(); serverVotes.voteTimeStart = DateTime.MinValue; serverVotes.loadStartTime = DateTime.Now; diff --git a/SharedLibrary/Commands/NativeCommands.cs b/SharedLibrary/Commands/NativeCommands.cs index d1e18659b..2c1993957 100644 --- a/SharedLibrary/Commands/NativeCommands.cs +++ b/SharedLibrary/Commands/NativeCommands.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Text; using System.Linq; -using SharedLibrary; using SharedLibrary.Network; using System.Threading.Tasks; @@ -12,22 +11,22 @@ namespace SharedLibrary.Commands { public CQuit(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } - public override async Task ExecuteAsync(Event E) + public override Task ExecuteAsync(Event E) { - E.Owner.Manager.Stop(); + return Task.Run(() => { E.Owner.Manager.Stop(); }); } } - class Owner : Command + class COwner : Command { - public Owner(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public COwner(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } public override async Task ExecuteAsync(Event E) { if (E.Owner.Manager.GetClientDatabase().GetOwner() == null) { - E.Origin.setLevel(Player.Permission.Owner); + E.Origin.SetLevel(Player.Permission.Owner); await E.Origin.Tell("Congratulations, you have claimed ownership of this server!"); E.Owner.owner = E.Origin; E.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Origin); @@ -74,7 +73,7 @@ namespace SharedLibrary.Commands if (E.Origin.Level > E.Target.Level) await E.Target.Kick(E.Target.lastOffense, E.Origin); else - await E.Origin.Tell("You cannot kick " + E.Target.Name); + await E.Origin.Tell($"You cannot kick {E.Target.Name}"); } } @@ -84,7 +83,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { - await E.Owner.Broadcast("^1" + E.Origin.Name + " - ^6" + E.Data + "^7"); + await E.Owner.Broadcast($"^:{E.Origin.Name} - ^6{E.Data}^7"); } } @@ -284,31 +283,15 @@ namespace SharedLibrary.Commands if (newPerm == Player.Permission.Owner && E.Origin.Level != Player.Permission.Console) newPerm = Player.Permission.Banned; - bool playerInOtherServer = false; - if (newPerm > Player.Permission.Banned) { - E.Target.setLevel(newPerm); - // prevent saving of old permissions on disconnect - // todo: manager DB - foreach (var server in E.Owner.Manager.GetServers()) - { - foreach (var player in server.GetPlayersAsList()) - { - if (player != null && player.NetworkID == E.Target.NetworkID) - { - player.setLevel(newPerm); - await E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm); - playerInOtherServer = true; - } - } - } + var ActiveClient = E.Owner.Manager.GetActiveClients().First(p => p.NetworkID == E.Target.NetworkID); + ActiveClient?.SetLevel(newPerm); - if (!playerInOtherServer) - await E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm); - await E.Origin.Tell(E.Target.Name + " was successfully promoted!"); - - //NEEED TO MOVE + await ActiveClient?.Tell("Congratulations! You have been promoted to ^3" + newPerm); + await E.Origin.Tell($"{E.Target.Name} was successfully promoted!"); + + E.Target.SetLevel(newPerm); E.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Target); } @@ -398,7 +381,7 @@ namespace SharedLibrary.Commands foreach (Player P in db_players) { - String mesg = String.Format("[^3{0}^7] [^3@{1}^7] - [{2}^7] - {3} | last seen {4} ago", P.Name, P.DatabaseID, SharedLibrary.Utilities.levelToColor(P.Level), P.IP, P.getLastConnection()); + String mesg = String.Format("[^3{0}^7] [^3@{1}^7] - [{2}^7] - {3} | last seen {4} ago", P.Name, P.DatabaseID, SharedLibrary.Utilities.levelToColor(P.Level), P.IP, P.GetLastConnection()); await E.Origin.Tell(mesg); } } @@ -516,14 +499,14 @@ namespace SharedLibrary.Commands if (E.Target.Level == Player.Permission.Flagged) { - E.Target.setLevel(Player.Permission.User); + E.Target.SetLevel(Player.Permission.User); await E.Origin.Tell("You have ^5unflagged ^7" + E.Target.Name); } else { E.Data = Utilities.RemoveWords(E.Data, 1); - E.Target.setLevel(Player.Permission.Flagged); + E.Target.SetLevel(Player.Permission.Flagged); E.Owner.Manager.GetClientPenalties().AddPenalty(new Penalty(Penalty.Type.Flag, E.Data, E.Target.NetworkID, E.Origin.NetworkID, DateTime.Now, E.Target.IP)); await E.Origin.Tell("You have ^5flagged ^7" + E.Target.Name); } diff --git a/SharedLibrary/Event.cs b/SharedLibrary/Event.cs index c47ce1729..d182d72e7 100644 --- a/SharedLibrary/Event.cs +++ b/SharedLibrary/Event.cs @@ -16,12 +16,6 @@ namespace SharedLibrary } - public String timeString() - { - return Time.ToShortTimeString(); - } - - //public Player Origin { get; private set; } public String Message { get; private set; } public DateTime Time { get; private set; } public string Name; @@ -30,7 +24,7 @@ namespace SharedLibrary [Serializable] public struct RestEvent { - public RestEvent(eType Ty, eVersion V, string M, string T, string O, string Ta) + public RestEvent(EventType Ty, EventVersion V, string M, string T, string O, string Ta) { Type = Ty; Version = V; @@ -42,20 +36,20 @@ namespace SharedLibrary ID = Math.Abs(DateTime.Now.GetHashCode()); } - public enum eType + public enum EventType { NOTIFICATION, STATUS, ALERT, } - public enum eVersion + public enum EventVersion { IW4MAdmin } - public eType Type; - public eVersion Version; + public EventType Type; + public EventVersion Version; public string Message; public string Title; public string Origin; diff --git a/SharedLibrary/File.cs b/SharedLibrary/File.cs index 7900dee92..f81b9b28c 100644 --- a/SharedLibrary/File.cs +++ b/SharedLibrary/File.cs @@ -10,86 +10,30 @@ namespace SharedLibrary { public IFile(String fileName) { - //Not safe for directories with more than one folder but meh - string[] asd = fileName.Split('/'); - - if (asd[0] != "") - _Directory = asd[0]; - else - _Directory = asd[2]; - - Name = (fileName.Split('/'))[fileName.Split('/').Length - 1]; - - - try - { - Handle = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); - sze = Handle.BaseStream.Length; - } - - catch - { - //Console.WriteLine("Unable to open log file for writing!"); - } - } - - public IFile(String file, bool write) - { - Name = file; - writeHandle = new StreamWriter(new FileStream(Name, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); - sze = 0; - } - - public IFile() - { - WebClient request = new WebClient(); - string url = $"http://raidmax.org/logs/IW4X/games_mp.log"; - byte[] newFileData = request.DownloadData(url); - - Handle = new StreamReader(new MemoryStream(newFileData)); + Name = fileName; + Handle = new StreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); sze = Handle.BaseStream.Length; } - public long getSize() + public long Length() { sze = Handle.BaseStream.Length; return sze; } - public void Write(String line) - { - if (writeHandle != null) - { - try - { - writeHandle.WriteLine(line); - writeHandle.Flush(); - } - - catch (Exception E) - { - Console.WriteLine("Error during flush", E.Message); - } - } - } - - public void Close() { - if (Handle != null) - Handle.Close(); - if (writeHandle != null) - writeHandle.Close(); + Handle?.Close(); } - public String[] readAll() + public String[] ReadAllLines() { - return Handle.ReadToEnd().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + return Handle?.ReadToEnd().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); } - public String getLines() + public String GetText() { - return Handle.ReadToEnd(); + return Handle?.ReadToEnd(); } public String[] Tail(int lineCount) @@ -122,8 +66,6 @@ namespace SharedLibrary private long sze; private String Name; - private String _Directory; private StreamReader Handle; - private StreamWriter writeHandle; } } diff --git a/SharedLibrary/Interfaces/IManager.cs b/SharedLibrary/Interfaces/IManager.cs index 412014fdc..b5d80ea15 100644 --- a/SharedLibrary/Interfaces/IManager.cs +++ b/SharedLibrary/Interfaces/IManager.cs @@ -14,5 +14,6 @@ namespace SharedLibrary.Interfaces ClientsDB GetClientDatabase(); AliasesDB GetAliasesDatabase(); IList GetMessageTokens(); + IList GetActiveClients(); } } diff --git a/SharedLibrary/Player.cs b/SharedLibrary/Player.cs index 4d56e9da5..df986b9d0 100644 --- a/SharedLibrary/Player.cs +++ b/SharedLibrary/Player.cs @@ -122,23 +122,23 @@ namespace SharedLibrary return $"{Name}::{NetworkID}"; } - public String getLastConnection() + public String GetLastConnection() { return Utilities.timePassed(LastConnection); } - public void updateName(String n) + public void UpdateName(String n) { if (n.Trim() != String.Empty) Name = n; } - public void updateIP(String I) + public void SetIP(String I) { IP = I; } - public void setLevel(Permission Perm) + public void SetLevel(Permission Perm) { Level = Perm; } @@ -184,6 +184,5 @@ namespace SharedLibrary public int Warnings; public Aliases Alias; public bool Masked; - public int selectedServer; } } diff --git a/SharedLibrary/RCON.cs b/SharedLibrary/RCON.cs index 804b00d15..07eef67b6 100644 --- a/SharedLibrary/RCON.cs +++ b/SharedLibrary/RCON.cs @@ -25,7 +25,7 @@ namespace SharedLibrary.Network var ServerOOBConnection = new UdpClient(); ServerOOBConnection.Client.SendTimeout = 1000; ServerOOBConnection.Client.ReceiveTimeout = 1000; - var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.getIP()), QueryServer.getPort()); + var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort()); string QueryString = String.Empty; diff --git a/SharedLibrary/Server.cs b/SharedLibrary/Server.cs index 9e6b95dc7..ae77ffd0d 100644 --- a/SharedLibrary/Server.cs +++ b/SharedLibrary/Server.cs @@ -26,21 +26,21 @@ namespace SharedLibrary Players = new List(new Player[18]); events = new Queue(); Reports = new List(); - playerHistory = new Queue(); + PlayerHistory = new Queue(); ChatHistory = new List(); lastWebChat = DateTime.Now; nextMessage = 0; - initMacros(); - initMessages(); - initMaps(); - initRules(); + InitializeTokens(); + InitializeAutoMessages(); + InitializeMaps(); + InitializeRules(); var commands = mgr.GetCommands(); owner = Manager.GetClientDatabase().GetOwner(); if (owner == null) - commands.Add(new Owner("owner", "claim ownership of the server", "owner", Player.Permission.User, 0, false)); + commands.Add(new COwner("owner", "claim ownership of the server", "owner", Player.Permission.User, 0, false)); commands.Add(new CQuit("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, 0, false)); commands.Add(new CKick("kick", "kick a player by name. syntax: !kick .", "k", Player.Permission.Trusted, 2, true)); @@ -73,25 +73,14 @@ namespace SharedLibrary commands.Add(new CFindAllPlayers("findall", "find a player by their aliase(s). syntax: !findall ", "fa", Player.Permission.Moderator, 1, false)); } - //Returns the current server name -- *STRING* - public String getName() - { - return Hostname; - } - - public String getGametype() - { - return Gametype; - } - //Returns current server IP set by `net_ip` -- *STRING* - public String getIP() + public String GetIP() { return IP; } //Returns current server port set by `net_port` -- *INT* - public int getPort() + public int GetPort() { return Port; } @@ -109,7 +98,7 @@ namespace SharedLibrary /// Player to scan for aliases abstract public List GetAliases(Player Origin); - public List getPlayerAliases(Player Origin) + public List GetPlayerAliases(Player Origin) { List databaseIDs = new List(); @@ -284,36 +273,20 @@ namespace SharedLibrary await this.ExecuteCommandAsync($"map {newMap.Name}"); } - public void webChat(Player P, String Message) - { - DateTime requestTime = DateTime.Now; - - if ((requestTime - lastWebChat).TotalSeconds > 1) - { - Broadcast("^1[WEBCHAT] ^5" + P.Name + "^7 - " + Message); - - if (Message.Length > 50) - Message = Message.Substring(0, 50) + "..."; - - ChatHistory.Add(new Chat(P.Name, Utilities.StripColors(Message), DateTime.Now)); - lastWebChat = DateTime.Now; - } - } - ///

/// Initalize the macro variables /// - abstract public void initMacros(); + abstract public void InitializeTokens(); /// /// Read the map configuration /// - protected void initMaps() + protected void InitializeMaps() { maps = new List(); IFile mapfile = new IFile("config/maps.cfg"); - String[] _maps = mapfile.readAll(); + String[] _maps = mapfile.ReadAllLines(); mapfile.Close(); if (_maps.Length > 2) // readAll returns minimum one empty string { @@ -333,13 +306,14 @@ namespace SharedLibrary /// /// Initialize the messages to be broadcasted + /// todo: this needs to be a serialized file /// - protected void initMessages() + protected void InitializeAutoMessages() { messages = new List(); IFile messageCFG = new IFile("config/messages.cfg"); - String[] lines = messageCFG.readAll(); + String[] lines = messageCFG.ReadAllLines(); messageCFG.Close(); if (lines.Length < 2) //readAll returns minimum one empty string @@ -370,13 +344,14 @@ namespace SharedLibrary /// /// Initialize the rules configuration + /// todo: this needs to be a serialized file /// - protected void initRules() + protected void InitializeRules() { rules = new List(); IFile ruleFile = new IFile("config/rules.cfg"); - String[] _rules = ruleFile.readAll(); + String[] _rules = ruleFile.ReadAllLines(); ruleFile.Close(); if (_rules.Length > 2) // readAll returns minimum one empty string { @@ -400,7 +375,7 @@ namespace SharedLibrary /// /// Load up the built in commands /// - abstract public void initCommands(); + abstract public void InitializeCommands(); //Objects public Interfaces.IManager Manager { get; protected set; } @@ -414,7 +389,7 @@ namespace SharedLibrary public int totalKills = 0; public List Reports; public List ChatHistory; - public Queue playerHistory { get; private set; } + public Queue PlayerHistory { get; private set; } protected int ConnectionErrors; protected DateTime LastPoll; diff --git a/SharedLibrary/WebService.cs b/SharedLibrary/WebService.cs index b5786ef56..34403dada 100644 --- a/SharedLibrary/WebService.cs +++ b/SharedLibrary/WebService.cs @@ -7,11 +7,11 @@ namespace SharedLibrary { public class WebService { - public static List pageList { get; private set; } + public static List PageList { get; private set; } public static void Init() { - pageList = new List(); + PageList = new List(); } } @@ -24,10 +24,10 @@ namespace SharedLibrary public interface IPage { - string getPath(); - string getName(); - HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers); - bool isVisible(); + string GetPath(); + string GetName(); + HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers); + bool Visible(); } public abstract class HTMLPage : IPage @@ -44,57 +44,57 @@ namespace SharedLibrary this.visible = visible; } - protected string getContentType() + protected string GetContentType() { return "text/html"; } - protected string loadFile(string filename) + protected string LoadFile(string filename) { string s; IFile HTML = new IFile(filename); - s = HTML.getLines(); + s = HTML.GetText(); HTML.Close(); return s; } - protected string loadHeader() + protected string LoadHeader() { - return loadFile("webfront\\header.html"); + return LoadFile("webfront\\header.html"); } - protected string loadFooter() + protected string LoadFooter() { - return loadFile("webfront\\footer.html"); + return LoadFile("webfront\\footer.html"); } - public bool isVisible() + public bool Visible() { return visible; } - virtual public string getPath() + virtual public string GetPath() { return ""; } - abstract public string getName(); - virtual public Dictionary getHeaders(IDictionary requestHeaders) + abstract public string GetName(); + virtual public Dictionary GetHeaders(IDictionary requestHeaders) { return new Dictionary(); } - abstract public string getContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers); + abstract public string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers); - public HttpResponse getPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) { HttpResponse resp = new HttpResponse() { - content = getContent(querySet, headers), - contentType = getContentType(), - additionalHeaders = getHeaders(headers) + content = GetContent(querySet, headers), + contentType = GetContentType(), + additionalHeaders = GetHeaders(headers) }; return resp; }