diff --git a/Admin/Application.csproj b/Admin/Application.csproj index a33717bfa..e8822e813 100644 --- a/Admin/Application.csproj +++ b/Admin/Application.csproj @@ -174,9 +174,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -187,7 +184,7 @@ PreserveNewest - PreserveNewest + Always PreserveNewest diff --git a/Admin/Kayak.cs b/Admin/Kayak.cs index 12dc5213a..94ecdfdd4 100644 --- a/Admin/Kayak.cs +++ b/Admin/Kayak.cs @@ -69,7 +69,10 @@ namespace IW4MAdmin catch (Exception e) { - ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request: {e.Message}"); + ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request"); + ApplicationManager.GetInstance().Logger.WriteDebug($"Message: {e.Message}"); + ApplicationManager.GetInstance().Logger.WriteDebug($"Stack Trace: {e.StackTrace}"); + response.OnResponse(new HttpResponseHead() { Status = "500 Internal Server Error", diff --git a/Admin/Manager.cs b/Admin/Manager.cs index 7a90b3b77..cd310d233 100644 --- a/Admin/Manager.cs +++ b/Admin/Manager.cs @@ -28,6 +28,7 @@ namespace IW4MAdmin List MessageTokens; Kayak.IScheduler webServiceTask; Thread WebThread; + List PrivilegedClients; #if FTP_LOG const int UPDATE_FREQUENCY = 15000; #else @@ -179,11 +180,17 @@ namespace IW4MAdmin WebThread.Start(); #endregion + #region ADMINS + PrivilegedClients = GetClientDatabase().GetAdmins(); + #endregion + + Running = true; } public void Start() { + var a = Utilities.DateTimeSQLite(DateTime.MinValue); while (Running) { for (int i = 0; i < TaskStatuses.Count; i++) @@ -197,7 +204,7 @@ namespace IW4MAdmin } } - Thread.Sleep(300); + Thread.Sleep(UPDATE_FREQUENCY); } #if !DEBUG foreach (var S in Servers) @@ -277,6 +284,11 @@ namespace IW4MAdmin return allAliases; } + public IList GetPrivilegedClients() + { + return PrivilegedClients; + } + private void GetAliases(List returnAliases, Aliases currentAlias) { foreach (String IP in currentAlias.IPS) diff --git a/Admin/Server.cs b/Admin/Server.cs index 92f3324ec..bb5345c7c 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -291,6 +291,9 @@ namespace IW4MAdmin async Task PollPlayersAsync() { +#if DEBUG + return Players.Where(p => p != null).Count(); +#endif var CurrentPlayers = await this.GetStatusAsync(); for (int i = 0; i < Players.Count; i++) @@ -357,15 +360,15 @@ namespace IW4MAdmin tickTime = DateTime.Now; } - if ((lastCount - playerCountStart).TotalMinutes > 4) + if ((lastCount - playerCountStart).TotalMinutes >= 15) { - while (PlayerHistory.Count > 144) // 12 times a minute for 12 hours + while (PlayerHistory.Count > 48) // 4 times a hour for 12 hours PlayerHistory.Dequeue(); - PlayerHistory.Enqueue(new SharedLibrary.Helpers.PlayerHistory(lastCount, ClientNum)); + PlayerHistory.Enqueue(new SharedLibrary.Helpers.PlayerHistory(ClientNum)); playerCountStart = DateTime.Now; } - if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 /*&& ClientNum > 0*/) + if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 && ClientNum > 0) { await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage])); NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage + 1; @@ -489,7 +492,7 @@ namespace IW4MAdmin } #if DEBUG basepath.Value = (GameName == Game.IW4) ? - @"\\tsclient\K\MW2" : + @"\\tsclient\J\WIN7_10.25\MW2" : @"\\tsclient\G\Program Files (x86)\Steam\SteamApps\common\Call of Duty 4"; #endif string mainPath = (GameName == Game.IW4) ? "userraw" : "main"; diff --git a/Admin/WebService.cs b/Admin/WebService.cs index 2e31c1c94..25d7a80ce 100644 --- a/Admin/WebService.cs +++ b/Admin/WebService.cs @@ -22,6 +22,7 @@ namespace IW4MAdmin SharedLibrary.WebService.PageList.Add(new Pages()); SharedLibrary.WebService.PageList.Add(new Homepage()); SharedLibrary.WebService.PageList.Add(new ServersJSON()); + SharedLibrary.WebService.PageList.Add(new PlayerHistoryJSON()); SharedLibrary.WebService.PageList.Add(new Penalties()); SharedLibrary.WebService.PageList.Add(new PenaltiesJSON()); SharedLibrary.WebService.PageList.Add(new Players()); @@ -57,7 +58,7 @@ namespace IW4MAdmin catch (Exception e) { - ApplicationManager.GetInstance().Logger.WriteError($"Unable to start webservice ( port is probably in use ): {e.Message}"); + ApplicationManager.GetInstance().Logger.WriteError($"Unable to start webservice ( port is probably in use ): {e.Message}"); } } @@ -196,6 +197,7 @@ namespace IW4MAdmin { var info = new List(); + int i = 0; foreach (Server S in ApplicationManager.GetInstance().Servers) { ServerInfo eachServer = new ServerInfo() @@ -207,10 +209,16 @@ namespace IW4MAdmin gameType = Utilities.GetLocalizedGametype(S.Gametype), currentPlayers = S.GetPlayersAsList().Count, chatHistory = S.ChatHistory, - players = new List() + players = new List(), + ID = i }; - bool authed = ApplicationManager.GetInstance().GetClientDatabase().GetAdmins().FindAll(x => x.IP == querySet["IP"] && x.Level > Player.Permission.Trusted).Count > 0 - || querySet["IP"] == "127.0.0.1"; + + i++; + + bool authed = ApplicationManager.GetInstance().GetPrivilegedClients() + .Where(x => x.IP == querySet["IP"]) + .Where(x => x.Level > Player.Permission.Trusted).Count() > 0 + || querySet["IP"] == "127.0.0.1"; foreach (Player P in S.GetPlayersAsList()) { @@ -226,7 +234,6 @@ namespace IW4MAdmin info.Add(eachServer); } - HttpResponse resp = new HttpResponse() { contentType = GetContentType(), @@ -247,6 +254,54 @@ namespace IW4MAdmin } } + + class PlayerHistoryJSON : IPage + { + public string GetName() + { + return "Player History"; + } + + public string GetPath() + { + return "/_playerhistory"; + } + + public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers) + { + + var history = new SharedLibrary.Helpers.PlayerHistory[0]; + try + { + int id = Int32.Parse(querySet["server"]); + history = ApplicationManager.GetInstance().GetServers()[id].PlayerHistory.ToArray(); + } + + catch (Exception) + { + + } + + HttpResponse resp = new HttpResponse() + { + contentType = GetContentType(), + content = Newtonsoft.Json.JsonConvert.SerializeObject(history), + additionalHeaders = new Dictionary() + }; + return resp; + } + + public string GetContentType() + { + return "application/json"; + } + + public bool Visible() + { + return false; + } + } + class Info : IPage { public string GetName() @@ -412,7 +467,8 @@ namespace IW4MAdmin penaltyTime = Utilities.GetTimePassed(p.When), penaltyType = p.BType.ToString(), playerName = penalized.Name, - playerID = penalized.DatabaseID + playerID = penalized.DatabaseID, + Expires = p.Expires > DateTime.Now ? (p.Expires - DateTime.Now).TimeSpanText() : "" }; if (admin.NetworkID == penalized.NetworkID) @@ -644,7 +700,7 @@ namespace IW4MAdmin PageInfo pi = new PageInfo() { - pagePath = p.GetPath(), + pagePath = p.GetPath(), pageName = p.GetName(), visible = p.Visible() }; @@ -670,7 +726,7 @@ namespace IW4MAdmin return false; } } - + class GetPlayer : IPage { public string GetContentType() @@ -718,7 +774,7 @@ namespace IW4MAdmin else if (querySet["recent"] != null) { - matchedPlayers = ApplicationManager.GetInstance().GetClientDatabase().GetRecentPlayers(); + matchedPlayers = ApplicationManager.GetInstance().GetClientDatabase().GetRecentPlayers(); recent = true; } @@ -780,6 +836,7 @@ namespace IW4MAdmin public int maxPlayers; public List chatHistory; public List players; + public int ID; } [Serializable] @@ -825,6 +882,7 @@ namespace IW4MAdmin public string penaltyType; public string penaltyReason; public string penaltyTime; + public string Expires; } [Serializable] diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll index b819a852d..52329072a 100644 Binary files a/Admin/lib/SharedLibrary.dll and b/Admin/lib/SharedLibrary.dll differ diff --git a/Admin/version.txt b/Admin/version.txt index 9a0030d4d..dca5454e6 100644 --- a/Admin/version.txt +++ b/Admin/version.txt @@ -1,4 +1,11 @@ -VERSION 1.4 +Versino 1.5 +CHANGELOG: +-added back player history graphs (past 12 hours every 15 minutes) +-fixed issue with configurationmanager files and threading +-servers on webfront listed in descending player count +-fixed resolution of tempban times from console feedback + +VERSION 1.4 CHANGELOG: -works: with COD, WaW, MW3, BO1 (preliminary without extensive testing) -fixed the issue with webfront chat history diff --git a/Admin/webfront/graph.html b/Admin/webfront/graph.html deleted file mode 100644 index a1d26a701..000000000 --- a/Admin/webfront/graph.html +++ /dev/null @@ -1,58 +0,0 @@ - - -{{GRAPH}} diff --git a/Admin/webfront/header.html b/Admin/webfront/header.html index 989efcc04..aca2ff546 100644 --- a/Admin/webfront/header.html +++ b/Admin/webfront/header.html @@ -8,6 +8,7 @@ + diff --git a/Admin/webfront/main.css b/Admin/webfront/main.css index 111990e20..1020dbed8 100644 --- a/Admin/webfront/main.css +++ b/Admin/webfront/main.css @@ -15,7 +15,7 @@ div#header #navContainer .navEntry a { padding: 1.2vw; width: 4vw; } div#header #navContainer .navEntry:hover { background-color: rgb(34, 34, 34); } div#content { margin: 3em 10%; } -div#content .serverContainer { background-color: #191919; margin: 2em 0; font-size: 1.25vw; } +div#content .serverContainer { background-color: #191919; margin-top 0; margin-bottom: 0; font-size: 1.25vw; padding-bottom: 100px; } div#content hr { border-width: 0; height: 0.25em; background-color: #007ACC; } div#content .serverInfo { width: 100%; } div#content .serverInfo .tableCell { padding: 0 0.5em; } @@ -31,13 +31,15 @@ div#content .chatPlayerName { font-weight: bold; font-size: 1.1vw; color:#fff; p div#content .chatPlayerMessage {font-size: 1.1vw; color: #fff; opacity: 1; } div#content .playerPenalty, div#content .playerInfo { margin: 0 auto; padding: 1em 10px; background-color: #181818; width: calc(100% - 20px); } -div#content .penaltyName { width: 14.28%; } +div#content .penaltyName { width: 15%; } div#content .penaltyName a:link, div#content .penaltyName a:visited, div#content .playerInfo a:link, div#content .playerInfo a:visited { color: rgb(0, 122, 204) !important; } div#content .penaltyName a:hover, div#content .playerInfo a:hover { color: rgb(255, 255, 255) !important; opacity: 0.75; } -div#content .penaltyTime { text-align: right; width: 12.5%; } +div#content .penaltyTime { text-align: left; width:8%; } +div#content .penaltyOrigin {width: 12%;} +div#content .penaltyRemaining { text-align: right; width: 10%:} div#content .playerPenalty .penaltyTime { opacity: 0.5; } -div#content .penaltyType { width: 12.5%; } -div#content .penaltyReason { width: 50%; } +div#content .penaltyType { width: 10%; } +div#content .penaltyReason { width: 45%; } div#content .playerPenalty .tableCell { } div#content .penaltyHeader, div#content .contentHeader { width: calc(100% - 20px); background-color: #007ACC; font-size: 15pt; padding: 0.5em 10px; } div#content .alternate_1 { background-color: rgb(34, 34, 34); } @@ -199,3 +201,5 @@ div#footer { position: fixed; bottom: 0.5em; right: 0.5em; opacity: 0.5; } .admin-name a { font-size: 14pt; color: #007ACC !important; } .admin-name a:hover { color: #fff !important; } .clients { margin: 0.5em; } +.canvasjs-chart-credit { display: none; } +.player-history { margin-top: -100px; height: 100px; } \ No newline at end of file diff --git a/Admin/webfront/main.html b/Admin/webfront/main.html index d17cdf0ae..cc58c003b 100644 --- a/Admin/webfront/main.html +++ b/Admin/webfront/main.html @@ -1,31 +1,101 @@
diff --git a/Admin/webfront/penalties.html b/Admin/webfront/penalties.html index ffcedb978..4a7ffa75f 100644 --- a/Admin/webfront/penalties.html +++ b/Admin/webfront/penalties.html @@ -34,6 +34,7 @@ function getPenalties(from)
"+ penalty['penaltyReason'] + "
\
"+ getColorForLevel(penalty['adminLevel'], penalty['adminName']) + "
\
"+ penalty['penaltyTime'] + "
\ +
" + penalty['Expires'] + "
\ " ) }); @@ -51,6 +52,7 @@ $( document ).ready(function() {
Reason
Admin
Time
+
Remaining
diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln index 16ba56c85..70259908c 100644 --- a/IW4MAdmin.sln +++ b/IW4MAdmin.sln @@ -39,6 +39,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Plugins\Tests\Tests.csproj", "{B8C2A759-8663-4F6F-9BA4-19595F5E12C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -303,6 +305,38 @@ Global {1479DE87-ACB5-4046-81C8-A0BA5041227D}.Release-Stable|x64.Build.0 = Release|Any CPU {1479DE87-ACB5-4046-81C8-A0BA5041227D}.Release-Stable|x86.ActiveCfg = Release|Any CPU {1479DE87-ACB5-4046-81C8-A0BA5041227D}.Release-Stable|x86.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|x64.ActiveCfg = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|x64.Build.0 = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|x86.ActiveCfg = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Debug|x86.Build.0 = Debug|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|Any CPU.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|x64.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|x64.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|x86.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release|x86.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|Any CPU.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|Any CPU.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|Mixed Platforms.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|Mixed Platforms.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|x64.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|x64.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|x86.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Nightly|x86.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|Any CPU.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|Any CPU.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|Mixed Platforms.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|Mixed Platforms.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|x64.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|x64.Build.0 = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|x86.ActiveCfg = Release|Any CPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1}.Release-Stable|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -314,5 +348,6 @@ Global {E46C85BD-A99C-484E-BCCE-0F1831C5925E} = {26E8B310-269E-46D4-A612-24601F16065F} {C9E821BF-23AD-4CB5-B7F9-B3B99B606650} = {26E8B310-269E-46D4-A612-24601F16065F} {1479DE87-ACB5-4046-81C8-A0BA5041227D} = {26E8B310-269E-46D4-A612-24601F16065F} + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1} = {26E8B310-269E-46D4-A612-24601F16065F} EndGlobalSection EndGlobal diff --git a/Plugins/Tests/Plugin.cs b/Plugins/Tests/Plugin.cs new file mode 100644 index 000000000..2585566d7 --- /dev/null +++ b/Plugins/Tests/Plugin.cs @@ -0,0 +1,78 @@ +#if DEBUG +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SharedLibrary; +using SharedLibrary.Interfaces; +using SharedLibrary.Helpers; + +namespace IW4MAdmin.Plugins +{ + public class Tests : IPlugin + { + public string Name => "Dev Tests"; + + public float Version => 0.1f; + + public string Author => "RaidMax"; + + private static DateTime Interval; + + public async Task OnEventAsync(Event E, Server S) + { + if (E.Type == Event.GType.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 < 48) + { + S.PlayerHistory.Enqueue(new PlayerHistory(time, rand.Next(7, 18))); + time = time.AddMinutes(15); + } + }); + #endregion + } + } + + public async Task OnLoadAsync() + { + Interval = DateTime.Now; + } + + public async Task OnTickAsync(Server S) + { + if ((DateTime.Now - Interval).TotalSeconds > 5) + { + var rand = new Random(); + int index = rand.Next(0, 17); + var p = new Player($"Test_{index}", "_test", index, (int)Player.Permission.User) + { + Ping = 1 + }; + + p.SetIP("127.0.0.1"); + + if (S.Players.ElementAt(index) != null) + await S.RemovePlayer(index); + await S.AddPlayer(p); + + Interval = DateTime.Now; + } + } + + public async Task OnUnloadAsync() + { + + } + } +} +#endif \ No newline at end of file diff --git a/Plugins/Tests/Properties/AssemblyInfo.cs b/Plugins/Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..1d901a309 --- /dev/null +++ b/Plugins/Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b8c2a759-8663-4f6f-9ba4-19595f5e12c1")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Plugins/Tests/Tests.csproj b/Plugins/Tests/Tests.csproj new file mode 100644 index 000000000..3d11308fb --- /dev/null +++ b/Plugins/Tests/Tests.csproj @@ -0,0 +1,56 @@ + + + + + Debug + AnyCPU + {B8C2A759-8663-4F6F-9BA4-19595F5E12C1} + Library + Properties + Tests + Tests + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + {d51eeceb-438a-47da-870f-7d7b41bc24d6} + SharedLibrary + + + + + copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)BUILD\plugins\" + + \ No newline at end of file diff --git a/SharedLibrary/Helpers/ConfigurationManager.cs b/SharedLibrary/Helpers/ConfigurationManager.cs index 60c1500d8..fa111d1ec 100644 --- a/SharedLibrary/Helpers/ConfigurationManager.cs +++ b/SharedLibrary/Helpers/ConfigurationManager.cs @@ -1,35 +1,38 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; namespace SharedLibrary.Helpers { public class ConfigurationManager { - Dictionary> ConfigurationSet; + ConcurrentDictionary> ConfigurationSet; Type PluginType; public ConfigurationManager(Type PluginType) { - ConfigurationSet = new Dictionary>(); + ConfigurationSet = new ConcurrentDictionary>(); this.PluginType = PluginType; } public void AddConfiguration(Server S) { + /* if (ConfigurationSet.ContainsKey(S.ToString())) + { + S.Logger.WriteWarning($"not adding server configuration for {S} as it already exists"); + return; + }*/ + try { var Config = Interfaces.Serialize>.Read($"config/{PluginType.ToString()}_{S.ToString()}.cfg"); - lock (ConfigurationSet) - { - ConfigurationSet.Add(S.ToString(), Config); - } + ConfigurationSet.TryAdd(S.ToString(), Config); } catch (Exceptions.SerializeException) { - ConfigurationSet.Add(S.ToString(), new Dictionary()); + ConfigurationSet.TryAdd(S.ToString(), new Dictionary()); } - } public void AddProperty(Server S, KeyValuePair Property) diff --git a/SharedLibrary/Helpers/PlayerHistory.cs b/SharedLibrary/Helpers/PlayerHistory.cs index 427f4a119..7a5da5f19 100644 --- a/SharedLibrary/Helpers/PlayerHistory.cs +++ b/SharedLibrary/Helpers/PlayerHistory.cs @@ -4,12 +4,45 @@ namespace SharedLibrary.Helpers { public class PlayerHistory { - public PlayerHistory(DateTime w, int cNum) + public PlayerHistory(int cNum) { - When = w; - Players = cNum; + DateTime t = DateTime.UtcNow; + When = new DateTime(t.Year, t.Month, t.Day, t.Hour, 5 * (int)Math.Round(t.Minute / 5.0), 0); + PlayerCount = cNum; + } + +#if DEBUG + public PlayerHistory(DateTime t, int cNum) + { + When = new DateTime(t.Year, t.Month, t.Day, t.Hour, 15 * (int)Math.Round(t.Minute / 15.0), 0); + PlayerCount = cNum; + } +#endif + + private DateTime When; + private int PlayerCount; + + /// + /// Used by CanvasJS as a point on the x axis + /// + public double x + { + get + { + return (When - DateTime.MinValue).TotalSeconds; + } + } + + + /// + /// Used by CanvasJS as a point on the y axis + /// + public int y + { + get + { + return PlayerCount; + } } - public DateTime When { get; private set; } - public int Players { get; private set; } } } diff --git a/SharedLibrary/Interfaces/IManager.cs b/SharedLibrary/Interfaces/IManager.cs index 99913c335..ad359af8f 100644 --- a/SharedLibrary/Interfaces/IManager.cs +++ b/SharedLibrary/Interfaces/IManager.cs @@ -17,5 +17,6 @@ namespace SharedLibrary.Interfaces IList GetActiveClients(); IList GetAliasClients(Player player); IList GetAliases(Player player); + IList GetPrivilegedClients(); } } diff --git a/SharedLibrary/RCON.cs b/SharedLibrary/RCON.cs index b47e1480e..4abf57987 100644 --- a/SharedLibrary/RCON.cs +++ b/SharedLibrary/RCON.cs @@ -98,7 +98,7 @@ namespace SharedLibrary.Network if (LineSplit.Length != 3) { - var e = new Exceptions.DvarException("DVAR does not exist"); + var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist"); e.Data["dvar_name"] = dvarName; throw e; } diff --git a/SharedLibrary/Utilities.cs b/SharedLibrary/Utilities.cs index 7048a55d7..c57ffcd58 100644 --- a/SharedLibrary/Utilities.cs +++ b/SharedLibrary/Utilities.cs @@ -293,16 +293,18 @@ namespace SharedLibrary public static string TimeSpanText(this TimeSpan span) { - if (span.TotalMinutes < 6) - return $"{span.Minutes} minutes"; - else if (span.TotalHours < 24) - return $"{span.Hours} hours"; - else if (span.TotalDays < 7) - return $"{span.Days} days"; - else if (span.TotalDays > 7 && span.TotalDays < 365) - return $"{Math.Ceiling(span.Days / 7.0)} weeks"; - else if (span.TotalDays >= 365) - return $"{Math.Ceiling(span.Days / 365.0)} years"; + if (span.TotalMinutes < 60) + return $"{span.Minutes} minute(s)"; + else if (span.Hours >= 1 && span.TotalHours < 24) + return $"{span.Hours} hour(s)"; + else if (span.TotalDays >= 1 && span.TotalDays < 7) + return $"{span.Days} day(s)"; + else if (span.TotalDays >= 7 && span.TotalDays < 365) + return $"{Math.Ceiling(span.Days / 7.0)} week(s)"; + else if (span.TotalDays >= 365 && span.TotalDays < 36500) + return $"{Math.Ceiling(span.Days / 365.0)} year(s)"; + else if (span.TotalDays >= 36500) + return "Forever"; return "1 hour"; }