From 063449d9c4e5ef4192b9e5f37c1fd7eea935a3da Mon Sep 17 00:00:00 2001 From: RaidMax Date: Wed, 31 May 2017 00:31:56 -0500 Subject: [PATCH] reworked some stats, redid the macro -> Tokens added reset stats commands broadcast for some commands --- Admin/Manager.cs | 8 + Admin/PenaltyList.cs | 2 +- Admin/Server.cs | 91 +++++----- Admin/WebService.cs | 14 +- Admin/lib/SharedLibrary.dll | Bin 95232 -> 96768 bytes SharedLibrary/Commands/NativeCommands.cs | 84 ++++++---- SharedLibrary/Database.cs | 12 +- SharedLibrary/Event.cs | 3 +- SharedLibrary/Interfaces/IManager.cs | 1 + SharedLibrary/MessageToken.cs | 24 +++ SharedLibrary/Penalty.cs | 10 +- SharedLibrary/Player.cs | 46 +++-- SharedLibrary/Server.cs | 32 ++-- SharedLibrary/SharedLibrary.csproj | 1 + SharedLibrary/Utilities.cs | 22 +-- Stats Plugin/Plugin.cs | 204 ++++++++++++++--------- Votemap Plugin/Plugin.cs | 8 +- 17 files changed, 322 insertions(+), 240 deletions(-) create mode 100644 SharedLibrary/MessageToken.cs diff --git a/Admin/Manager.cs b/Admin/Manager.cs index 56014d90b..ac72bff73 100644 --- a/Admin/Manager.cs +++ b/Admin/Manager.cs @@ -22,6 +22,7 @@ namespace IW4MAdmin Database AliasesDatabase; SharedLibrary.Interfaces.IPenaltyList ClientPenalties; List Commands; + List MessageTokens; Kayak.IScheduler webServiceTask; Thread WebThread; public SharedLibrary.Interfaces.ILogger Logger { get; private set; } @@ -38,6 +39,7 @@ namespace IW4MAdmin Servers = new List(); Commands = new List(); TaskStatuses = new List(); + MessageTokens = new List(); ClientDatabase = new ClientsDB("Database/clients.rm"); AliasesDatabase = new AliasesDB("Database/aliases.rm"); @@ -106,6 +108,7 @@ namespace IW4MAdmin { Name = "Web Thread" }; + WebThread.Start(); Running = true; @@ -162,5 +165,10 @@ namespace IW4MAdmin { return Logger; } + + public IList GetMessageTokens() + { + return MessageTokens; + } } } diff --git a/Admin/PenaltyList.cs b/Admin/PenaltyList.cs index cc7ebc6ca..d6c969132 100644 --- a/Admin/PenaltyList.cs +++ b/Admin/PenaltyList.cs @@ -20,7 +20,7 @@ namespace IW4MAdmin public void RemovePenalty(Penalty P) { - Manager.GetInstance().GetClientDatabase().RemoveBan(P.npID); + Manager.GetInstance().GetClientDatabase().RemoveBan(P.OffenderID); } public List FindPenalties(Player P) diff --git a/Admin/Server.cs b/Admin/Server.cs index fabac6d4b..ed554c55e 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -40,7 +40,7 @@ namespace IW4MAdmin if (Origin == null) return allAliases; - Aliases currentIdentityAliases = Manager.GetAliasesDatabase().GetPlayerAliases(Origin.databaseID); + Aliases currentIdentityAliases = Manager.GetAliasesDatabase().GetPlayerAliases(Origin.DatabaseID); if (currentIdentityAliases == null) return allAliases; @@ -51,50 +51,50 @@ namespace IW4MAdmin override public async Task AddPlayer(Player P) { - if (P.clientID < 0 || P.clientID > (Players.Count-1) || P.Ping < 1 || P.Ping == 999) // invalid index + if (P.ClientID < 0 || P.ClientID > (Players.Count-1) || P.Ping < 1 || P.Ping == 999) // invalid index return false; - if (Players[P.clientID] != null && Players[P.clientID].npID == P.npID) // if someone has left and a new person has taken their spot between polls + if (Players[P.ClientID] != null && Players[P.ClientID].NetworkID == P.NetworkID) // if someone has left and a new person has taken their spot between polls { // update their ping - Players[P.clientID].Ping = P.Ping; + Players[P.ClientID].Ping = P.Ping; return true; } - Logger.WriteDebug($"Client slot #{P.clientID} now reserved"); + Logger.WriteDebug($"Client slot #{P.ClientID} now reserved"); try { - Player NewPlayer = Manager.GetClientDatabase().GetPlayer(P.npID, P.clientID); + Player NewPlayer = Manager.GetClientDatabase().GetPlayer(P.NetworkID, P.ClientID); if (NewPlayer == null) // first time connecting { - Logger.WriteDebug($"Client slot #{P.clientID} first time connecting"); + Logger.WriteDebug($"Client slot #{P.ClientID} first time connecting"); Manager.GetClientDatabase().AddPlayer(P); - NewPlayer = Manager.GetClientDatabase().GetPlayer(P.npID, P.clientID); - Manager.GetAliasesDatabase().AddPlayerAliases(new Aliases(NewPlayer.databaseID, NewPlayer.Name, NewPlayer.IP)); + NewPlayer = Manager.GetClientDatabase().GetPlayer(P.NetworkID, P.ClientID); + Manager.GetAliasesDatabase().AddPlayerAliases(new Aliases(NewPlayer.DatabaseID, NewPlayer.Name, NewPlayer.IP)); } List Admins = Manager.GetClientDatabase().GetAdmins(); if (Admins.Find(x => x.Name == P.Name) != null) { - if ((Admins.Find(x => x.Name == P.Name).npID != P.npID) && NewPlayer.Level < Player.Permission.Moderator) - await this.ExecuteCommandAsync("clientkick " + P.clientID + " \"Please do not impersonate an admin^7\""); + if ((Admins.Find(x => x.Name == P.Name).NetworkID != P.NetworkID) && NewPlayer.Level < Player.Permission.Moderator) + await this.ExecuteCommandAsync("clientkick " + P.ClientID + " \"Please do not impersonate an admin^7\""); } // below this needs to be optimized ~ 425ms runtime NewPlayer.updateName(P.Name.Trim()); - NewPlayer.Alias = Manager.GetAliasesDatabase().GetPlayerAliases(NewPlayer.databaseID); + NewPlayer.Alias = Manager.GetAliasesDatabase().GetPlayerAliases(NewPlayer.DatabaseID); if (NewPlayer.Alias == null) { - Manager.GetAliasesDatabase().AddPlayerAliases(new Aliases(NewPlayer.databaseID, NewPlayer.Name, NewPlayer.IP)); - NewPlayer.Alias = Manager.GetAliasesDatabase().GetPlayerAliases(NewPlayer.databaseID); + Manager.GetAliasesDatabase().AddPlayerAliases(new Aliases(NewPlayer.DatabaseID, NewPlayer.Name, NewPlayer.IP)); + NewPlayer.Alias = Manager.GetAliasesDatabase().GetPlayerAliases(NewPlayer.DatabaseID); } if (P.lastEvent == null || P.lastEvent.Owner == null) - NewPlayer.lastEvent = new Event(Event.GType.Say, null, NewPlayer, null, this); // this is messy but its throwing an error when they've started it too late + NewPlayer.lastEvent = new Event(Event.GType.Say, null, NewPlayer, null, this); // this is messy but its throwing an error when they've started in too late else NewPlayer.lastEvent = P.lastEvent; @@ -120,7 +120,7 @@ namespace IW4MAdmin if (NewPlayer.Level == Player.Permission.Banned) // their guid is already banned so no need to check aliases { - Logger.WriteInfo($"Banned client {P.Name}::{P.npID} trying to connect..."); + Logger.WriteInfo($"Banned client {P.Name}::{P.NetworkID} trying to connect..."); await NewPlayer.Kick(NewPlayer.lastOffense != null ? "^7Previously banned for ^5 " + NewPlayer.lastOffense : "^7Previous Ban", NewPlayer); return true; @@ -140,19 +140,19 @@ namespace IW4MAdmin if (B != null && B.BType == Penalty.Type.Ban) { - Logger.WriteDebug($"Banned client {aP.Name}::{aP.npID} is connecting with new alias {NewPlayer.Name}"); + Logger.WriteDebug($"Banned client {aP.Name}::{aP.NetworkID} is connecting with new alias {NewPlayer.Name}"); NewPlayer.lastOffense = String.Format("Evading ( {0} )", aP.Name); await NewPlayer.Ban(B.Reason != null ? "^7Previously banned for ^5 " + B.Reason : "^7Previous Ban", NewPlayer); - Players[NewPlayer.clientID] = null; + Players[NewPlayer.ClientID] = null; return true; } } - Players[NewPlayer.clientID] = null; - Players[NewPlayer.clientID] = NewPlayer; - Logger.WriteInfo($"Client {NewPlayer.Name}::{NewPlayer.npID} connecting..."); // they're clean + Players[NewPlayer.ClientID] = null; + Players[NewPlayer.ClientID] = NewPlayer; + Logger.WriteInfo($"Client {NewPlayer.Name}::{NewPlayer.NetworkID} connecting..."); // they're clean // todo: get this out of here while (chatHistory.Count > Math.Ceiling((double)ClientNum / 2)) @@ -168,7 +168,7 @@ namespace IW4MAdmin catch (Exception E) { - Manager.GetLogger().WriteError($"Unable to add player {P.Name}::{P.npID}"); + Manager.GetLogger().WriteError($"Unable to add player {P.Name}::{P.NetworkID}"); Manager.GetLogger().WriteDebug(E.StackTrace); return false; } @@ -183,7 +183,7 @@ namespace IW4MAdmin Leaving.Connections++; Manager.GetClientDatabase().UpdatePlayer(Leaving); - Logger.WriteInfo($"Client {Leaving.Name}::{Leaving.npID} disconnecting..."); + Logger.WriteInfo($"Client {Leaving.Name}::{Leaving.NetworkID} disconnecting..."); await ExecuteEvent(new Event(Event.GType.Disconnect, "", Leaving, null, this)); Players[cNum] = null; @@ -241,6 +241,7 @@ namespace IW4MAdmin override public async Task ValidateCommand(Event E) { string CommandString = E.Data.Substring(1, E.Data.Length - 1).Split(' ')[0]; + E.Message = E.Data; Command C = null; foreach (Command cmd in Manager.GetCommands()) @@ -270,14 +271,11 @@ namespace IW4MAdmin throw new SharedLibrary.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\""); } - if (C.needsTarget) + if (C.needsTarget || Args.Length > 0) { int cNum = -1; int.TryParse(Args[0], out cNum); - // this is so ugly wtf is it doing here? - if (C.Name == "stats" && Args.Length == 1) - E.Target = E.Origin; if (Args[0] == String.Empty) return C; @@ -346,7 +344,7 @@ namespace IW4MAdmin for (int i = 0; i < Players.Count; i++) { - if (CurrentPlayers.Find(p => p.clientID == i) == null && Players[i] != null) + if (CurrentPlayers.Find(p => p.ClientID == i) == null && Players[i] != null) await RemovePlayer(i); } @@ -397,8 +395,7 @@ namespace IW4MAdmin if (lastMessage.TotalSeconds > messageTime && messages.Count > 0 && Players.Count > 0) { - initMacros(); // somethings dynamically change so we have to re-init the dictionary - await Broadcast(Utilities.LoadMacro(Macros, messages[nextMessage])); + await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), messages[nextMessage])); if (nextMessage == (messages.Count - 1)) nextMessage = 0; else @@ -653,7 +650,7 @@ namespace IW4MAdmin await Target.Kick("Too many warnings!", Origin); else { - Penalty newPenalty = new Penalty(Penalty.Type.Warning, Reason.StripColors(), Target.npID, Origin.npID, DateTime.Now, Target.IP); + Penalty newPenalty = new Penalty(Penalty.Type.Warning, Reason.StripColors(), Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP); Manager.GetClientPenalties().AddPenalty(newPenalty); Target.Warnings++; String Message = String.Format("^1WARNING ^7[^3{0}^7]: ^3{1}^7, {2}", Target.Warnings, Target.Name, Target.lastOffense); @@ -663,21 +660,21 @@ namespace IW4MAdmin public override async Task Kick(String Reason, Player Target, Player Origin) { - if (Target.clientID > -1) + if (Target.ClientID > -1) { String Message = "^1Player Kicked: ^5" + Reason; - Penalty newPenalty = new Penalty(Penalty.Type.Kick, Reason.StripColors().Trim(), Target.npID, Origin.npID, DateTime.Now, Target.IP); + Penalty newPenalty = new Penalty(Penalty.Type.Kick, Reason.StripColors().Trim(), Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP); Manager.GetClientPenalties().AddPenalty(newPenalty); - await this.ExecuteCommandAsync("clientkick " + Target.clientID + " \"" + Message + "^7\""); + await this.ExecuteCommandAsync("clientkick " + Target.ClientID + " \"" + Message + "^7\""); } } public override async Task TempBan(String Reason, Player Target, Player Origin) { - if (Target.clientID > -1) + if (Target.ClientID > -1) { - await this.ExecuteCommandAsync($"tempbanclient {Target.clientID } \"^1Player Temporarily Banned: ^5{ Reason } (1 hour)\""); - Penalty newPenalty = new Penalty(Penalty.Type.TempBan, Reason.StripColors(), Target.npID, Origin.npID, DateTime.Now, Target.IP); + await this.ExecuteCommandAsync($"tempbanclient {Target.ClientID } \"^1Player Temporarily Banned: ^5{ Reason } (1 hour)\""); + Penalty newPenalty = new Penalty(Penalty.Type.TempBan, Reason.StripColors(), Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP); await Task.Run(() => { Manager.GetClientPenalties().AddPenalty(newPenalty); @@ -696,7 +693,7 @@ namespace IW4MAdmin { Logger.WriteError("Ban target is null"); Logger.WriteDebug($"Message: {Message}"); - Logger.WriteDebug($"Origin: {Origin.Name}::{Origin.npID}"); + Logger.WriteDebug($"Origin: {Origin.Name}::{Origin.NetworkID}"); return; } @@ -705,16 +702,16 @@ namespace IW4MAdmin { if (server.getPlayers().Count > 0) { - var activeClient = server.getPlayers().Find(x => x.npID == Target.npID); + var activeClient = server.getPlayers().Find(x => x.NetworkID == Target.NetworkID); if (activeClient != null) - await server.ExecuteCommandAsync("tempbanclient " + activeClient.clientID + " \"" + Message + "^7" + GetWebsiteString() + "^7\""); + await server.ExecuteCommandAsync("tempbanclient " + activeClient.ClientID + " \"" + Message + "^7" + GetWebsiteString() + "^7\""); } } if (Origin != null) { Target.setLevel(Player.Permission.Banned); - Penalty newBan = new Penalty(Penalty.Type.Ban, Target.lastOffense, Target.npID, Origin.npID, DateTime.Now, Target.IP); + Penalty newBan = new Penalty(Penalty.Type.Ban, Target.lastOffense, Target.NetworkID, Origin.NetworkID, DateTime.Now, Target.IP); await Task.Run(() => { @@ -727,14 +724,14 @@ namespace IW4MAdmin List toRemove = new List(); foreach (Report R in Reports) { - if (R.Target.npID == Target.npID) + if (R.Target.NetworkID == Target.NetworkID) toRemove.Add(R); } foreach (Report R in toRemove) { Reports.Remove(R); - Logger.WriteInfo("Removing report for banned GUID - " + R.Origin.npID); + Logger.WriteInfo("Removing report for banned GUID - " + R.Origin.NetworkID); } } } @@ -753,7 +750,7 @@ namespace IW4MAdmin Manager.GetClientPenalties().RemovePenalty(PenaltyToRemove); - Player P = Manager.GetClientDatabase().GetPlayer(Target.npID, -1); + Player P = Manager.GetClientDatabase().GetPlayer(Target.NetworkID, -1); P.setLevel(Player.Permission.User); Manager.GetClientDatabase().UpdatePlayer(P); }); @@ -789,10 +786,8 @@ namespace IW4MAdmin override public void initMacros() { - Macros = new Dictionary(); - Macros.Add("TOTALPLAYERS", Manager.GetClientDatabase().TotalPlayers()); - Macros.Add("TOTALKILLS", totalKills); - Macros.Add("VERSION", IW4MAdmin.Program.Version); + Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYERS", Manager.GetClientDatabase().TotalPlayers().ToString)); + Manager.GetMessageTokens().Add(new MessageToken("VERSION", Program.Version.ToString)); } override public void initCommands() diff --git a/Admin/WebService.cs b/Admin/WebService.cs index 8169ca52e..b1cc1048a 100644 --- a/Admin/WebService.cs +++ b/Admin/WebService.cs @@ -196,7 +196,7 @@ namespace IW4MAdmin foreach (Player P in S.getPlayers()) { PlayerInfo pInfo = new PlayerInfo(); - pInfo.playerID = P.databaseID; + pInfo.playerID = P.DatabaseID; pInfo.playerName = P.Name; pInfo.playerLevel = P.Level.ToString(); eachServer.players.Add(pInfo); @@ -366,8 +366,8 @@ namespace IW4MAdmin foreach (var p in selectedPenalties) { - Player admin = Manager.GetInstance().GetClientDatabase().GetPlayer(p.bannedByID, 0); - Player penalized = Manager.GetInstance().GetClientDatabase().GetPlayer(p.npID, 0); + Player admin = Manager.GetInstance().GetClientDatabase().GetPlayer(p.PenaltyOriginID, 0); + Player penalized = Manager.GetInstance().GetClientDatabase().GetPlayer(p.OffenderID, 0); if (admin == null && penalized == null) continue; if (admin == null) @@ -379,8 +379,8 @@ namespace IW4MAdmin pInfo.penaltyTime = SharedLibrary.Utilities.timePassed(p.When); pInfo.penaltyType = p.BType.ToString(); pInfo.playerName = penalized.Name; - pInfo.playerID = penalized.databaseID; - if (admin.npID == penalized.npID) + pInfo.playerID = penalized.DatabaseID; + if (admin.NetworkID == penalized.NetworkID) { pInfo.adminName = "IW4MAdmin"; pInfo.adminLevel = Player.Permission.Console.ToString(); @@ -621,11 +621,11 @@ namespace IW4MAdmin var playerAliases = Manager.GetInstance().Servers.First().GetAliases(pp); PlayerInfo eachPlayer = new PlayerInfo(); - eachPlayer.playerID = pp.databaseID; + eachPlayer.playerID = pp.DatabaseID; eachPlayer.playerIP = pp.IP; eachPlayer.playerLevel = pp.Level.ToString(); eachPlayer.playerName = pp.Name; - eachPlayer.playernpID = pp.npID; + eachPlayer.playernpID = pp.NetworkID; eachPlayer.forumID = -1; eachPlayer.authed = authed; eachPlayer.showV2Features = false; diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll index 3f11576194c06ba89a84c2f22040f760e3f0eaf1..d3567c03102310cb12b14402ee667d09595c1d2a 100644 GIT binary patch literal 96768 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

^qZ_v=dvY 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

>bXj)9ucyC;-{@kjec7blG(a>;#))|Pa zVzs*4K%)gp_;pP_w5V2o!)2U6FPr|h7ULV8rn&q&l@zfi$KSi9(EPz*8xr2U7%f~8rnmk zkBro_1X|o*)Akl})N^gxdF3l9{r&hbE%)-OF!%sSr#C9DfQ zP=mGB1NFBq@<0Qvi#^Z~>rxLi+`7yIjkd1vKpobV9%zzvwFjDFUF(6SS=W1@8P<&+ zXiw{A4>a4l)dTHs-R^-FSa*1!gRQ#+nuZaZ25-5?Lp#*^od-%=_j{lf*6%(3ahzDA2J?4QjP4HykoyciO9|)d_^v;mq zZ>bXBE(kDO8M&GIjA!~Na|Xtxks4gFM{OuVfX@2_Y1A9@T*J8i61F7&k0^; zVXpxUcQlt&IBJ*LE0C@$BWAJSt7}<4x|!*ZzHpE=uR)zZ`iZHoy%FW3o0)!-d<#38 zfmQ5lr|7Ln$=On~1~A>Gd_6FO%kM$Wa0S~oCYWw$B+r4B4*)-+g_yeoOs|n1N7s^i zyV!)EiH%=;a-U>4za=bWLryiyUHJ3$6uqv6PRKR@#QM z#F9sgRmX&>%brp8eo)KfknPM$_WqPedsF>W!2BU_0n)j3wY&Ws5!~1^({5b=@K--Ct?=fCWVQ0U3 zw}ri|lu>&+gg-5&ju6|{h>mxP7O(*DH-NuiwN!+Iesx+|44BVjmsx&wK^ZYmHYI@h zkN)(WZ$#he@DOmr$okc+^8VNh|F+)%q-R7g0H6CJl7QF!{v^h9l%&^{vAit8^q2Mj9m;k9q^ed26{PxeU@htd>X_al<)p*%n0luBNIImJk-E11o|4y*^K*vt z-Vv9|adD}R>KA2%!dvBEpb#Pp>5{~P$172{I(vD4Z;qv-i% z_GS4I{2#E)8;a4JJ(BZvNDqN`{ZH6@^Sb<9bQxjO8_Vq5H=|LD6*g4X>{+%d>poAN zM|+i@9G>o#`qQ=U%|EAEFK$MoytQBLRT4&$w-HIUP#^SIXSDS>_-|$R9ObmPe5dku z>rJnjE!do?lS7lrrebG3Tc97~03p-&WcxV`%BvJikvJ zYiMg?KUVtG37S^7s6J5TS9fbjeNj_Z<){Y@G_GPQPLMt@(4Q)QgpTuD75<%!cGXou zb*qNdD>d)o6zy3Jg?3I5dRd?~p}iB;fZjB;dwlQVOyWaBd&pM}=%0r64ro>CTSNN- zv?}ErApM2@So3aKwJH;6P3YO0epS_~*3kC!zo(+A$$Q z1khHR1|3FK)sQ{@Z3t`;m{e7-f!=)ZdJRg zOOYl%fwR*=0&P(2eYo0B)6^gPt*siaJ{cl4)ouN*0JI<8%s@Lpx8p0)r+DlN=;gYH zt46BNhUcNjt467{Jhm0uGgYJ2m7_GYwBL(WW7X0z8u}{vM%9+8W2}Z=Xm}UUIe3$U z?R*11uNtR5z?m|k=BBk(TdRAv($LZU)~l`6_XfJQ?g!AG+FH|o52!=k%0pnZyR^nv zJznh~r`RW}t7@v%1hu#Tg{vnPSz;S?rqHw{CaXJ4&4U`Nswb;a6Ex3*8spX5Dm0ZI zwgEIn&77p6VT~=-+o?wlv^$`wYT7nJ!?+Kw-d-)zka{Nip4w3zr=ie-GD4>av?g>o z=FN`k97C(Dc(?3lYOSFqEBaOaOkJsI;5njty85aBO{(5a4VujUE>uUg>|8xdUAt|* z_iDAb+HXo8npM4zIHc%C2?QAt;J87r5n#@rv4D?uRPW2r1 zO9KsTd=IqC4D?{^0MNFXD(z%$&Q;R{S`*^joU3-zG?@?c)cyr1T)m&_^t3xbWj*Z< zP$wE1=k0;&Oheqmo*Js4y#_IW^S)Fs%p$sAEIUpv?f&Fm<6=J&{q00)r-{Q1$~K)b5?X!U&oT3@|doyx-k%!gBaYkX&@s|~amQSnT*-axltRL)e-7-&9X z@>%L71Kk$esp=Q%4FkO&d#w6wHEKuAb6V`l>T}eo2D+u@$?9LKHw-jC@nrS+s^e$6 z=6cXBRA*^Od}6J-Kp^cCYt^NO#x-Z1y4ujV=B!h<7}^uQ^>~JOx1qh{3jli1(9Vl( zU-fJCxS?GFsei4W%hS;AV)crlU4eENtG5j8kf!zO67`XRj%o@3`och5t1eaFnRZ;O zE>-^NqEYB5$oU&pF3_6Lagg&jDsE^~}E-;Ib3*4)6B(K`+8(ZD_}ldA42)Z7Ws z-392%z%A;Y0`yyfW(b#))jwMvtG-8FY@qky<@c&D4U}kltQz00%fAhQX|ajX`wP%5 zH4~$MC_w80JzRk1CniQ8D?sjLAbYjS= zs0Q>qL%Tk4QuI0Xu%X?XI33WFhITaeS>mL1 zsiEx!uX{oL%h2ZcJ16>r+GJ>dh`gs>RL(4FyC(Ehq#96_KqrSbA-4WSB@HcH9stxL z(1mKphF?ctQo9)Ftmez2FRMicYHheG`ii>WK+9`yi2hZ5Z=ioQWrDA%GxuVD7pji{ zy{>U1^|SCGL&Bp{DPnY0XY1_?CKcj)qj#qtUn3I|lko z;L+$i>a)3;_GaLT=)39_eCdS#LXp;IvF5!Y(7B;x>#Kl1&@}Ap-i^Mmz7&XiK1+UI zhwU~5QnB|u5M#mnB;enMz?NknqMiP?A@FY5E$Tz{y@$((s%$?}$ukaGgFq*$e^9{W;t8EDtQ zwz03&3kIqQOpkq|2F=$sj|j|+eW#WRbgsIqaY5{R67X+B;Ht`M^@9cgidU) zb&o(7s?!6f#~kZ>f!?!NGic3Nz?vJZw=jM|%j<(Uj*)*G0^j)O`CTXw@Itx3IWd>E zWnf(_oNrgbJ3bt-Yc3U&YcGqr(0lN#h_#pWuH`I-%8F>^MH*FD`xn}cs;ab>3A91+ zezUfS7Ps#4&>D+q2+Ip8nr=6sh&Irg?x77Sq7Ajq@z6#U(MDS@duUr1(K@V_gWUcm z7tyx07JF#ZifB7pw|ZzZifFr9Uwde?ifDUTQx>`X%`KwMvrhHU78KDITF-iDi;HMW zth$3;p6MdmGHbqvwz7zJly$9#mMfyIvOe?BPAsCGWOe-9?eB~t+L_jB5ABylwDYXT zJ+yU2w2Lg<3gDj}_sfcCms_(vv}=lJ*IJi(Xg3$pZm~Y_(C#dv-DQnh?Dltm5$yr% zXbekqYR+p#UM@8*EvQ9NM z>+vqkN7gw4y=g6IwbaMfeuuI5H?6BHS^+IJ5NV%SQ4H z+E-THN|*MPl`;@%|F-b54*qHD{@bcH5NTgqFMDWTTOW96-&l7X?Y8^IdelH{_pLSP z7?<{~wWWbb`_B68SeN#lrLr0#?R)FNE|>Pb^{jzN`@wo4=hA+#-Z2nqo2)C3b7`Bb zI}AkHkJde_UD}V<;|3y4*{2@w(v-c{K%`mr^pjkgWzRMcX}0~;$u7;dUo#MCK6}!s zF3o4pFc4{e`{L7Gn%}oh8fk;c(pWN-z685(O>4=gn>OE;Y_ps&(YLt37mb7aH(h;T3Zn@9pQfH4c5PPV% zzy5cvL#`IYp=-@)%ms_r}oNX_%g$@8g_ zvQLevBp-h4k7&}uRM*t_xe;Q%jWN}HPJ?!q%1L^c=)P3i{s=j3wJY?+Oo6_ZqRf^$ zS*&!IaMl=|E}IKXV!e13%cNTBM$t%HTT7@%jpJ1; z51&cpE#n=Xb6_i5zGd>MCh5yd)#dHP@+;suwwmcs+6&OiufFdEulacE)7pOFA5dqD zY+kC%Eue0NHSi8M`UzRr_~Ru!_Z4a`YOY{9NV>nM?Nu)ltq8FRLRmVDm`m@fb7-heDMP@-YY=Q_XsrF&*?fr%4gH5D9 zDc-{GLa-(X|6$;hFKdif>!UF{EWDk;bdHQNF+S7Fe+{E~{z)WxTw)HTwZ+cGp4oT1 z>6-LdJm(kxKL+#B7H_l^%lTB#AdUH*c|E1aSkVNt~ zWzFIa%~Be3m#i1Pr4LKZ-l+e7#P_Dr%d)Z*YgC6{bZ*AJZHBs2?TTwRT)X3%iEB?> zvvBQ&Yj0fp;F^tV4z9Vl=Hc28*Z#N;z;z(5`M4I~T8Qf)T#IlWjO*vP4#Bk;*AiTZ z;yMi1Qe21QIs#W3*D_qoab<9I;#z@gC9b1z9gXW)Tv=RQxWbB0YobU4_$rKLybn~5 zF9?xV;|naN+ex~Uqr7kwd2)os;ptEx=!)Q#GBSzksX15CAtU7pZ4EJJtRD9)$jTrg}0}s z*Po^asR1p&2KA}_mq~gJFbi65!Pijt;2n}Tt*v6~k$w`rTRkUzJ*VRF2Y~ss|0C){ zYh`OS@DutyDQ%y_S8#1LFX6;17~P0dl<#Zs&b+n#fb}Tzjg$`+-=7KFM^=0!^=)gI z`mXiYc(dt;>MF~!F6v)vMeVkl28(??fchWd*`Otwvd3}2@0Of|nimG9TCKu!h<#-L zL#-`EHr6@Y8f{;J=ij64>Gc;{_11uvi>-C4HhP)$4P?90I!)d=S*ISXyv`bL53p~u z-n1?ra2Gh-5V#-psrw{wd&=6$UL1WM>7dpxQDm<^=wvV)<&VZ}`oS z-fN{!Ey_FF|6hCG0v^{@ox9JO8O`W5w#M&RwnrpR>?BtFN^B>_NFLdih-53)I1i#k z8qJKP!J`>@W@KA=z=$Ng%p*|XLJ1$rP2dt9EonkaZqr+tghJY+1Pa_zptVcjLT`Ar z;r8BJDEI%@K6}m?X{@BQ-~GOR_e$ScXYKdeYpuQZ+WYJ|hjp&^#U&;#spqZtZW#1^ zNIi)fK7=1TKc-IDkF81iD4i+a9^uj+>*0nweABjQkxl8Jx0+jLkmnQV;|$`@_&SmE zLxAyem8kZP$%>_7H@*7qpz-}gNMNi9`R*z54yTuSY%@2v3r34v$r zQAmeWeaSZnIs@vgoy8NyLG`V+A0USO97Nw=1b%YmKloDe%ZZfYsiG|Mlfx@FEb+7K z4*%PvN9V1t;I|zK>-q2@z$c@9fTK8LSrR@_$~*jb365WJf!cQne4oGv1U@Y7ej50* z;Qw=x@B1H@_&BtEN#IG*_Qxg9lcMKewR=|Y3hb2Br=77di)T_#JE{M1!@M1Pr&ylEkd>t!ZS7pIQ4^-;Y55QnlHB zb6X*}$LHU03h<@%ZwvlX@#*7c`@L=N4?dzUU42*m2`gClyDDM*Ebu1a&*0f>!usnK zAE-}Qe<3*c*X!+{ul{a*N&RB!la}8iC4P(N@%p!CY%ZAMjP1dEWV-3rtHowKQ z`N#vxTczgZsQJT~A4t_6`)`}y(2$Z}1+_|Bt!V2>t5vM-ONx}dq)5X{it#Tg(y+(+ zZ|i#+9~LdT5;g}mO)SYH>Mz>f)wt85?(LQMy%OK!3$1^;vB&q@_Qx?cpI!f_!2581 z@KN;;PEkCnUci~1N7emnA5+gton2D4OUe#POs~ZBIx)07ame~v>t6M#hPO8XLO<^n zjlEa$4@&+)$)A#(usO&X!Z#GQG>6m=t?hs>TDt&$X6*&^+l&v{jBm0Tzg%Kk1x6(v zzW_)4CY$-Mv^xQ}+6Mu5+Sdc_w)+A1+Q$Gp?AHNy*+YQcb_%f9&H(n?Il#DG1iaZk z4LEM!4VaZyCZ&~1h+#DKH^$M&PW#2L;XvJS*^=!1Dr? z%^EC$QGsm&I|OzL92S@mn6!_p*t)Xd_t@matl$p{oD+Cf;5mWH$NDe!G3T)0Wr4E- z=LDV;sQkjOkfoBCiCGecU^8&voP&KdyOQ26+o4|_& z#snq>-XriKflmqaHL~o*0%HOb0+Ryo5jZRGA%SxO&kB4>;CX@H6XjqXI7$7!#Nfm=t)Az=s4rCGdL!eM^L^0%HP`0`Czxx8#gk zgOitM)N7WjrDs%nc@*$n%R2xcUp~B)Wy=C*1yGL*TH$vcOq^a{|>e$tkcy;IP25z*!x$@{Ib{@-m=*#Vp|ED~4B{QSlXJz`Iur zuNKM$&I+6pcut^NBlQdH5I8KbEO1ufoWOGe)kTtDV28kAfn|ZS0_Oxq*U}D@1FbtIN))FRktX{N?I0;O;eZ zfQ2<`(;4-tH64KG*OUQQUo;0eaFN=4MxD8+1Mp8SDgy@A&H=t=t-Ab-dc)cdz|XBM z1O9039ALCnU2#SYwsru%r?m|DTuqgOFzSm3O{ za{{AVC0^jHz;gnl+azA#tiW>uquV83;H6l%NpA~pcV0kxV<^-xe#CKu^GpK%wH)>pJ^;kDrqgLK(v^(sZ z?KAer?8oiz+rPAz_*VEX_U-qL``+yPr0+@JSAF~Z!~VSg4gPofAMpPVe_P=C!0Q5; z!0EtS0v`_iZr}@nuLZspI2ZV*z=pcbb^GdKbvM_2u`U|CD!4D03?2{O6Z~-Slffr~ zUk?7);17bo2>L_ILaz#K3w4B!gl-Q_gzgHR3H^5HkTSjwvBK~lmf$TfOYwHU7W{rGqAo$qW%AyasM@ZSI@0)MJTv&| zhGzlqi#!i_%gS#6e$hwxj{?85>|4OIe#U&W`L6-L+eCbcv>eMDrS_EWmMISj~X%0pI~V%fo31KpPUM z2Ob8rA%#ZZ`28C27Np<_KcFr0!Bcyr+mK2N;#UINkk>Ncs{w6ze=C5u0^0b!*ec-b z0d4F;tpOedw6Tw~7Wk_GZTN}nfL{V=*JQ-C&hqOJfw4v60v;#XZ3_M^4{&*FVrc=8NrV@HZ_6UqbH z*p=D=`~;v4FY;>O_X67LKK#-O&!_=y^%m?nS?aBTHg<@v1O9eETb)s_2L28}JYQ0; z0sbyPJmE%HqLzU4M^_;#PczA2>1s8ZS_Ib1N=jPHh$A_J@5|$ z+E^j?0sjb~t)2oWEUcoB0RN)Ae+|&a+43RaUk9{tUOWN(n}D`@0o=9J_W^CZy~yA5yD< z52=fQ535$-!)iV7go*-Bs8<0WQI`N8QI`Tws!hO?>T=*IbtUkWY6qTHTY;z5cHpCG zC-6~q4e&9w8~B*I7WlZ@3w&Jd1D;VGz%yz;@Yky@;ICH)fge}hz>llf0?(>m;8}GT z_=M^QKB0~R@@oVpQs9-sT(2>3eSlWGw7q`DpW2{jD-gc<=}P$}RAe6;g2th2^} z7uD;5m+-#Ajet4eCshgfNp%wVDRmn7DRl?%)9NnZr_~#P-=W?N{0^)IFT+ah?ZEHE zn+-3+&h5K^-=*#cz6tHW3A!G#-eP^hI%z*^U+eoD->-Z@|Hu8G@qf<$NB%GRpYwmi z|6PA5uqLoC@Sg%#)$OYLtGXZ5^#|V-Y-_l#p|9cghC3TdjgL1z*%)f-YkE`DV@-Hp zNtwI<-ao!E3)|n7zew{}CCFSEC-2(kALA+T{CuC3eAQ)l!E(;ew_D2MQGey{lICmi zEJCRRu&D=OMGwJtcH`>7oc3B+&+B0udvW#QI*jWGu6|rMz)l{;HGnIQ>lm&Zaoq&l zcr&hBaJ>%Kt+)nZ=Wc^Vyd5@f2>cv|eM{i2Wh1a{N$l}rPX&6`4*j|cdbJh$v<>~; z4*l5yz1azUxf*(M4fJCd^kO&Uu?Ko^E#!Y4~#AM}3|Cqy5_*}9Kmcj7ViMtg;Ix&J|Rm4AbE z3|9u%XRctAJ|;*ZqOtwVHw(tj)M~2XV?bc-DFY@P~0dhU*KszKZJ{ zuAk!iXI#yp4OT0zD{x(ls|VN3xW;gu#C0F8_u+a7*YDvvi|ct@e}n5MxPFDJseXgC z7T4vt_TcKqbrY`9`sb{7;(7qr$8h})u0O!_XSlwO>*u)sH!fcT_VXM5yY>2p=dAyL z>*0ofvc8D>w{g9I>mPBc#^dwcVVR9|9pUutM*$5yp>-=3kN ztwTWClcjuN--r`p^fpExIGs*TmC~KX>0FYj61guqG}M(TPG%F+v23DP)R8E%okb3% zOGnembgtBo^mL)fVv@j0uW@qdG$u*RSlXLgqUN`Zn)eq#d@@lik^1f1)ZXMoYTwl$ zO6|=!_gwl^f4VT?hS*n~h2*9So!LyHm@YbTsga??{0N=T^Hd^Jl2C7^ zSVH99eY=K+P8AZ9K;!9bR(QHy#q&M6(vIz_r+>TJD}2OVm{4Hvx2uCwx#aM6b$xpJ z#zb~1-Ji%55bWv7BuklmE>W09s8TmjQ}?zV!1JA{iA=62Z6SPpCV8Crww($ZFw|ej zoJ24C(i8c@^g!m0^ff!x-hp|%L{vOIF$t2S;${ol`bVR+2TH!Lr1B) z_N!PngY+V>-k9pg50T|%uk0LO`dW1Eh4dJNkS;KeX{kghF#@%8vUq~=L}ARyl$&&t z1!1wIH0H!s0!$eZt=&KEqQe^~tC*wM zM`K40tHVd)JqLSYo$($74jqUO^&CEUL=8-X{E7CSBT`FGzw`{ZsY%eD27<}~Z%|Zv zC(nSBX+WwOhUQ;6`=m+ET7G$MH`FlhtfHWrKCENqu~?L13xCU=#bM{ul6YK$VT=!)Kq6a zDmriy%AspInogute7wLLNmH?-X?9HwIrq*~ zN*&B5#>Ubql}(hAaN{i&|a1fOs11!osgVKsl8C*eaDA} z_9v3Z@!I2qnRFJB6pq&Dg=y5^g|S9|7pAz{yD+V%zgFD9!btMxRKAc}m~wO~*Le~K zc`Us!tq&rtna~YO1Jkge--p4$g|XfFVkuWMh4NaMe}5c8SQvdYePSw2LD9%BOzuse zOlKEH7f>pL8Kko?c6e%HVY)V1HIr@{Pv;gEI8w-rWopE8;>{F`FpUe#^kUX_)UsxJ zSGt%iWF~1>7Z%1?Db|XQO%)0lP@Liy3Sw$vBwbh--h2C@ze4Sx_U<_)81=(w8``g;b*uCx~=uVN1DmI#s+-Vpn=Hol7NhHOftb zJM<71)~NlWZlqy$UXTn|OvMYCi37QmqHT-ki9s~Hb&WXYRl#S-z&4~!c;JR!xFwYk zs8XGiBu*X703->H=BEHL8H?RA16gL1N?_6%-e?Bd(!DAKQ zMhprpda-2Ea_Q3*99kpwfN`<$L=H8ATuyg!`hrq@=SjF75^|kJ`d`J#d{Lq^#Tzrl z46~nf?p^sQQ(7A?q0K?j2~Hq1IZn)}0%YRgXr3tt3;78rriV;ZoU0rJHXjkA1kmqd z9`|^r1bA@Z5Qc#e&G8_O3X;^Wn&6lxvT4CsjUcQ_5baI~s;38%A;F2nq})?*vju^a zbr%f|Ma+fOWqeYb=D(086YO4*LZM*VBR=$R;K+xAtYS*-SB=%;zw$Sc(-x z#R??}QL9Ugjva#;!=0m`H&A3pB#%HWOQ^LQdR3V2PZSWL{VWxO|5QRI440#MatVImwxJ zptPh!-Dx3;kQ2lMY^24kK6#t3y*6PpB(BGBq|vC3bV5urmbR zxK8+I6C>Ga85-VbtgOA#_9i(c3W-#DB2hT*CTYWdumE|%sqrLeYSM-7Oe&SmxdjfK zhQv8FyHSQ9${O6Rod~rV&5TVIWW}?vtY_MG6E*9k1bo@VX~Bwax@j0Lb80GCT9^>a zPfo+f7_XT$F`39syJZ~f#WvB-NG6*pc~bXJLtY1RaGR#|pph}5;9K96DUItuUnZv! z+7gXH&7iLuKgl%-v?7_#oRm7aFjYld^v+d3d|snz+MQ>Ftm^kqlRcQr7;_+pxrIn9 z4H|LJ6hV59nB!wRJ!yAj!4%O?E@Byo=Lg2~+SuqXjELXwph%Rjj&Phg*ud0CQO8Xb zovK7TFezg-Aqoy{)|ojWqCZoBNFAqr>F2!*!%IR#z3JQ-(EP~j6<6&_tOM-ZNC8X! z_QUBC^^gOxcwF06gH$=KVy>!V&=e|%=PGF$i@^d`;xv+#EOAVI3S&Oinazraz%sC?2ogj~NcMxDbH!3aT*(td6s^_MieX>J?DJYl87c~Cb zJd!YHNMT1il`$C->3aTBt0y=?UGsz;T|b0R-f)E}bgKO15R|n9M~(h}Wjv%uon^e@ z%r2wRooBQbd&1hJV|L&imM(ZwH~}2ZpYp_D^U4zvap)y8o2RoX>t~_G@lPueqOMho z8R>HM`i4xI7XvXIPJ@O@MX*@ht~zi!nU-Y_Sgtqy(r%P9tlS9hD!L)PCh>+#oR9f0 z4m&n5HIvivytZaNxzW6eafJZ|mq0cz8z69g3QU1tiP>E0ch`5)h9`(^US=A|rqh!u zGpSPsf^T&~k(^jIohZ;P!qY8qPb$VB#NtpYbx^vq-LNZ&?Gb&^c-M$0 zpf$`BVfM*%UTsRi2v!n@Pw$|e+&f>eEem4#l_+PE7H&&vXlO+5*mCd*ADeQwO2m|m~5n$eMQ6$jWBNq2fZx@qFm`j<5bf+Bj0G&U* z2*|@-A}={u(VrS(sfNBd({DA0(YbE%AJB{uJ)8gnBisVq6D0xOV!SfVPrO z0DX0^i7_qW&MEAHYY`vJW52b)MI;72;xGugNYMeASK@gckj@<_6qpJ9#zL3NPV5a4 zGaL8B(VnyTVo1y+G+O7ACn>5u$p#XYbhEPbLVtP*coSfnu- zAR6r)DH@&b$|S~eSiEGCh@y91nSUK)QY2v&JcFhyfiWmX94>NpK(An=S&8tjYn-{~ zCTx_=Z$jMtQLLqfVoXEC=D9ACCqGGgFJBNl!;fC_Oi9vYOzy*mGTT#kmlXXv^iK=trHRMq1cjbs>krb(0__4UVe`LqVXGCd9St zRMCW>0|rGlgCe%-5vxollVZa(J>B^!@Bk(BnAbtNznw`wrI0bB_cfj87TENH&818g zxFh#usUlnWA?*X=Pv}bB4N2*-CkQVckH4H@m!8CW1)6snwh`lr^B`BcQ$^);gub*B zLt5da>H518(;n(8A-HW+6ne*@khx_UJRYyi%k0}ak z8ca6&0frMZAafTh05LH{3GfGC=N*>m%D(=Gm7HaK)uDkmX>` zn9|Wb{Rc3kV@;vCNO_jhRZ%g_)etPKu*Q-ShN2W8^@FINH8aqI?IPUhkb*!s5K?77 zw2qI{sC}w(W&nyK16%8+uwgQx_qv5wl>mGY=qm<fYbxB|;hm85{PC19d5 zxk)7SK{pS>P#UG7(UjcIL@Z%Ch8X{Xi_2jGWd7m&DGpC@Gl5PdPOH>N4;;eN+D4ka z1r?uG1Bq#0=(Zl(i4&x+90iy=b1e{UrJR#5=7Q1L-$i>O3m?TE6NyREq<|u67a7EaY zgS-;l&XJi|3&R=xj%d_@iAf~$&)3FdUl;e`3HDVu`IG{j#(xy2uDWqDX#)S(;#5-+ zpG@t-DX9|A?ctPF9w(d%I4zaNS*JU3M(S?VbS171rLON$hmqp|&SS-qm!UY$X+?3) zO6ME~z6tm?l-dmZMjQm_#dGWfD5X=jOUiZlbZ;+CUggkA6lbn>gOaFeE%0ibs=^@w zoc`)U`8Y~fw?GQmzHTRqlVIIK6Z74P(_D9h@(u^{wzCH(yS(kR@jUDy*4B$FCUstp zIu4?LN5C~hQFRN$PP@ZSE9@)!v)1j;Hng+V+fr59Zg9s#MOE6KYEHZ<83QQ?Dolt2 z!zl{HL~-0L2CN4-g)o3)Z)7mz4?~a>U@T+Eyql$CQN$lZiC!FoW3C(yxAlO*i|0BF zWthP6xinOQIkm_S;P4)mAPNy3MO+`~I*NmMQ5@nsAootRMb%(_-G@GhQr&tlYCMT6 z>!~#gY7T(;EZZwIZ$*vORQIB9aM)1uDE`yvMG>&N57i}NQ0SZ}S`y_l5-Kj*>b3=~ z_Mo4OwPC2L)z)I=j@6JrHT8Yc-{a_GYEhcEI#NA~oa9JBxchQtHdAqDS{73>{OT7X z@TylF0`7;P7V8+vprFY5#q!lw!fF&V%?jW@?jQu8D~u{TP@U$9TP5%%p2@s_Wj2n zsd_WwRlQ-TYIH}KYW9v|waV00J%-e(TH1@rAwY(zpw?B@?A1u++XlmTne>>}z_cEP zX^hgi-taHsqt}ejuSriYsBweanzvV#7LWa=E!L{7((00Gxv0!<-io%(T5D)6qnN6U z{Hk?n2c|OB=%y;)Moh!_I?ljv+PbR~Q5;~VgepBOE>`C-2A(zpoZ!838m`EkDO&2L zPL2a=#W2Q3KcJh=DHF1+H$zbY(?&%#drgO0QETw4@>>=o){t7wOik3kW@wsvIViQ~ zVg1I+RxOBXwprF4Z|qdK8u%vuO?CxeTqQubQo18r^Qw{ielZzuY;-YILbpK{9GUsYPw= zVlC_Px(#EI7^i|AA_Rq>rdStKK@NdOF(}!Pa8NtbFPif2WL)h=)jF;N)xaokIw@LH_Xu0n|f^5I-7?x*pK71lF`_$;t7)N&PAeiMGN zax*Y|O-eXa1Z@+jq20-)HhO7D$-2(8J&HV2sAnAg$m6#xT!|Hwx-N-$woF^&#xtMh zaUO1W6m*Uwe-!17tBJDp>>+ue))|aLjZ|`hz`n3`K|R}_ zmU^RDcyPUHWY{h(P9w~<>Sk%yIYDTtq$W`+Q2Y2C-G@D_7RKF5NC%sU;=EQ$l)LQ|0%V z2#Pm>D}%<^Wu2iGOGZH!Rf?+=oIMbs)+Wc)ZR&bO>aX1cQ!87+C|@;-8b~>95${wt^kc}xYb)iZuqWIJVt#F- z*dnbVqe^vYE$V=R{@4p z^Azf3KUtHS_?Na{fHH9zZzdp9(}mi1+oJH;wyHmc9u-iBD&J$!`C>EXQCk8URL-@g zQ4&Gc)*hE`ov+AL`c6TwO&P7nBu`Cq43O2@9+(-#$b8`ZOEom z5IWT)=S(0f?c(z}rRUa^C<$!~tpi6Qy^aeB#nj71>t4yJ)pH8vRkJ%Vpe{+*mQ|~$ zoXHe|-s9WhV&BS9`v`0HkJL~#aw0=f=Yq#O1DL!hD?}k<8(GwkoJg zs3qQ#7>73)LrsgMwTd~&EIq4N=YKg`P-8tuNs+$$8@Vb-p(fX>(#)m?>t{RELE2lk zrUm5gWl$_`PIqiaC6=_#r-si>+Mqp7`}i6!6@YD# z+5}WLyHI0PU<5>|MwCt<>NHT+sx~;_X;F-HK)D0c@DX@aT|_7`ZESJ9gStNH+OEsi#rCfoq$&&1*jbgaF0M}1n}(wcL=-&8Z?LvU|zR6TST|v^&*4VspDk@ zIP-A9D9#`@I`l-Uf?OnGsz*AUieO4cn%;JT^8^o{u_s09s(uW4bJ&(q^_;VC#zd?M zO({1+RAUO;Qyj(c!~5Q{)`%m(9Y?BV03j~t>2%SmsB}A1S#xS5ALP} zx9T~`o2Tchu~T|4@>|v=lyPDEI;j`EXgP%1S-!G`xMTofS^;eX)Y<{5v49vJ)Zp$9 zxj-(f#y*jDC#BtT5bf&8RzKrY8*5376q5hc7W!Ih-SxQZ?XH+mMQg#H(>+&fOfQYp zSUwIJs*OBW!v8JU=<5TdhVz(-_mGLz@_O`7J0N;CQZ3xW((;{>eyEn}Fm$KcyU(SX z-90a)H8PFvHzeF>FzOrUOfJ6kT9?w)8?I)}sj$lhjm9{^21r1h`~c1(qZZv`iErkt zr$-1=Sc2RD-ptWNU6xv;%&5k%(mdLNzEhSd2Dv80)eI zbShb>eKmc2Ku^zF{G^IgKZhsZgyr@4Xfn4+jh;G}ky`HITm?!>5HmI~HlIS=2#g?y zC5PT1(%56ROFwwAoMgIDcTdiGyt^Id_Y#Qx*Z6)i|6OOqJoR&)*R3--qGC933Jo-n zuT)H{jl-9#B^n_ruy)moFvIlHA^2@aq4G!YxOQQh;WLHn)}aD4!0OdBfL!g8e%HyO zinx-Eq8)OV%Hnmn)H-iy2sLqdQB%as$2e3u$&zBzf|es)Pxj>wiHR&@* zd=#r{)}dQ{#dWNr8!`>L66i;?(u%s6dO)LMQmSP_{ZmV{OJyiimvza>v7@Mk)1-Ef zP2Z?hdVQ>xrG(c7Johlq2-Ffz?e4^GEvar#VOYB|SEsb08x!iN2Q-Lg0xHU(8Z$O% z%-tPc{ftD9$HkwM)Eb{E=8jLVbhWdqtw0Lgq`9MkW;~|`x1~1d`z<1Q>XTQy%w7>( zqg|cCd1@9XD!o$TlP7l)(>*ZDAI+-^)$BfLp}D1-dOJ?K(Pe@RH`k_y(&vQhF16HU zv={xtY4ex(5J15y4AGGCx$!lwoM&R8n~R$ClPtnj;S38@4#3yskb7$(-Y=X zO+6y7=7`*(OX(JL8C~AQbKIJ`bW5te+S^PL`# zoJ{q^NJ~mxr(Ac)eHU`OQ!z&axnQKO`>MwNt!m|Bj>|8tU7hHyc2S&m){HvT4`D=6 zH)%~|Tj+>h2C`S$Ijz+r9uH$pub@YXe|>!~)0Y(!pnVe7)1?^liPau8)%&Z{VteQW zYn#M98}m#BOXgb_x2yC}Oe?Nk33Dzm}|NBj(r8 zhS|FZb-QyjeE_z?M+>ZJ{(~O$VzYUA9rZlFHZwgn+-R%{^kFkWy|H$FW5eD4={Bpa zuIs?^K#H~{UU!$VdUU$B#p^u7@m*`I1CNau8{k;0je0raeHx;9s&#-`iDhnICpd0w zwyVE7XSD|CINC{fdx`ElHHx)i8Qpdm{H@+lqtvwfEOzEZEsAvVrB$Pk?r|+7F{+fBO zUznG^v)2#osB?Q?KUS&gn&sIEKe>Fwf{)-A<0p#j@!kNSnw(fi{bzw0}4CgoT#@xz<11|L3O;+;?>D&EJ0h>F+5YY^OhJS)l+x%L<}l0=o_%Qhr3= zK3BIQQnHpQKla-C{6VYbmXNYrZfWUj=|ct0fv6o0hZ*08vf(hk9S{z;E(_L&!;wTJ zv!dmM9c~SW?Z_1BNds?)suht5dzo5hA!fpfK{g#D`TbG6^SVy?P;)q_{Je$Hn2ig> z+ToCp97#x8YinyDsv_n8B~6Dx^)iqfjM|a%ufnY;680cG*b_LMD7j+f_5Yk3I_v`@=PRy&Xn&%CrFgj;C;fNndYXTpILNNMWp;TE7BEa?(#b$cenIK%I`6;b!6N+-IaHO>Q-N!u(TB%u$Bv*E;5DcL_Y|}sygC>}yi=dk&z4)z zQ_|nehDdWLK#C~GWh%5L7y^gq7Xm5o2?c#Z(cSD}xV6H>Cd871Gt0e9#MjjWHiZWUqsoyOdXQ zKr_~b*ZEjUs3}+nVm}g!YzjxFI7UK9MFhv1&5^S%j4ydv;g*>LEi*kWGksdEZV+9( z0h-VNO$@IKfK}@PBKdUzl!{D26~L1EsLiHYX41`0r@~>771I4iezgu`3ET@oVbD$p z!4Ok-g7bD=n4Nh)Bel!5PP<}MH)v~Om z>s6q^LNvxwnOSJ4~>no?@Wbma-dXEur$P71`vlz8iN) zDbmF-;`ci7QRlvtcf3@+YiU$hv zX+=dzY#q}T!9T{S)wM(1WP7Z zlHh3*JT1YyOz!Tnc({*_(2o=padT< z!3QKbYl5>9eAomZmf$B$@DmdJvK5v50OYkpE@Gm9!9TWVH1kah^ISKyI1b-;O7ftX*3I5Ck zf94O`^%$=H5GL#L6ENLTg?qzR+osW6y50&k*oc7XgxbTjo8V4^>^8_=gLFuBy;7Zt z>o!O)MjDLngH6FeDAMaRY7+Ym5;q72avdgS&Ip*|TgpGioD`YT!w7>#I}Oi3ZPzR4 z?K-i>&)}|Y=8sW~=8&Z@v1r5{cd#Z6G@wkDL52~B0+^sVL;LE`01Ql})uu{jj6QE* zd>Q!Xn46lpvv3wdRs1NK4xYwGYGFahdJ}b*LCOZX*C1~-$U6*jzd_yyH!>u%c^6D9 zDh#1Ux|$z>?`AT6aCNXgWJi`ta`_{g=B1IP!cxvUFx^_*4;W+?z7wWQ6MVQC0$~;k z&!zbjjuGy4W}jX$l^>&13NP3c{xmfM9y)uAnYg9TBzzY0iq=3&X@95+gfc;lcec!b*9P=O}i>kbw=nw7~ym8IWb8icM z`?v1=!q<=dd{1cWXO8^f_dfnRKlUs9`7HvQz(>GHKSZGXbp%0z5CJ9{3>1P!f+m7y zf-u1nf?wkg9)6Eq*KF6p*N+_Y*TI{$>ulbyBxogw5?q4xF1xP5Ul%DqNboVcuFmmn z!${kNs{>aS*SO>PMRp59r^&>08zgFy_M(8!$At;#xrMdT|3$);%%#07AoRja`9UXF z7_`i+ZeXfjhtwN1#1!2yolA70{3yW_jPH_q=$-))H>``j9BekTvdpI@ZK*+e4N{@F z!^CueAW=Y8|8*1F&Cm-7i7(iME;YdyvYH97(1M{oCSF8{qok)PS_hN49D0pK3{$zR zQi!3Of?FffnF!B{E9A(r$RuN+O8{xKCIlk%LR4K7;BNChCmbO|L%`ZlcMU zfjQ*LGl+ODF@&YG4T^L$A+(aC! zL$bEXSwD9P51M3Y#U4jG-0~g5f=EX&>O-$v`kIA1tx!nt01K7?SaJz$0secjArRSw z8KYNfve7UdKA8>R>B0Wgp%OTUA@Qxyk$P}ccM06E!2m3O;66HcEHeUZbLL7m6k-yY z4iB>>+UO1Sg>6!Oj1DDWq>Eh!5fE%|2u+eYH0rk^Sro3YqQk=$Xaj#xR$-0H< zyCr?M6HCGS;V6axtY-S_pactRa054Tg^O~nV&MQ|`UoRk^lnAGgAFL@ps-U`IBK`t z94UVTQQtysqD6G!op5s$PG}{yQ8`7y0W1sFp~1mOZx|Z~RGw#$NDmt^A*>mW;ogdw zT#%(wk~w7fLJ*1z)`~j!R6oyx2oP} zhf`RbN7O2OI*yCAiAJ|?-G(!moAJrZw595<7NZ zvn9P_WY4axqg%I+;`3Lk$x^{>?OXY;RF9=DYCn7+UU@0_mCmbrUwv|C`_&*dyu6a+ ze7uXVK8&zTw2~4<-i?-uR#DupU)Oep_ghZt!nr(ObyAz~Ql<;l<^71$BGq|5;-oII z)P~yC?RUNhg=Zm`TWVu zbYC!7v+Tl=;!;`p4n@t9i|AG5jrTPRE-D3nFQ#Ux#iXFWQBt$mwU)a2LcHP25cOMO zYZl#QsqGgms$c9~v)p1$x^LaBS#+PJ_FSk*7IojVTC@0K!enRV)xkAOF4l1M$9`%S zUradq3ve}yEi#7rIf|NP7H^7g$*fsyu`wd7(XV%{S$46J%uhtrEc9{>!bb6h@ioi7 zoE+ta%QZ_b)~b2IyUesspfZbLMxtYI&9>Bz-P`x1w~Qu7(pz@!Ozqe*GO{bVX?tItHOfc)@sjuqvf}GBrXH{@wg7 zJtOY2(0e)YXl>G4J^AoM=2*VamCg3y1=so`k?C|hKMlgaUvESmOKaEi?={wv4z0%T zLaTegRf@vz6&A)bUpKCsXDxhhoFVwf^1TA+zPc+zJQ7uIxI^6+;b`hO=5nSclCB9yf7y9RxJS09?dSwi`H zl_!nAhTwU#!?^P|A?B}3g^|m&*M$_klU(TFPrmefI+)k|c!{TkdJ)fe@UYML@eb&~ zQ|d|``o~&4UCFa${M&|8LR%{rc@{x_a!H@t%BtRh1+UJ>-;qW<;*&IK`-B* zlobw4f*O6`hQCCCtpNqqaZ&Y%isFAe=;5mwv9v-h-g>m8_zMi4Nh;uUq~WGQYi#p~ z(*`BQmJRP1(wu!I^zRkE_oJ>n`owdvB@YJ{=l4$GcXiqMT%XVL-BP9#z2VUs{;W-( d#(%kTVA21*zp|ycv%D9-`27EW|L<|&{{UIWk;VW3 diff --git a/SharedLibrary/Commands/NativeCommands.cs b/SharedLibrary/Commands/NativeCommands.cs index 2fff0fed3..6f13da132 100644 --- a/SharedLibrary/Commands/NativeCommands.cs +++ b/SharedLibrary/Commands/NativeCommands.cs @@ -7,9 +7,9 @@ using System.Threading.Tasks; namespace SharedLibrary.Commands { - class Quit : Command + class CQuit : Command { - public Quit(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + 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) { @@ -36,9 +36,9 @@ namespace SharedLibrary.Commands } } - class Warn : Command + class Cwarn : Command { - public Warn(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public Cwarn(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) { @@ -50,9 +50,9 @@ namespace SharedLibrary.Commands } } - class WarnClear : Command + class CWarnClear : Command { - public WarnClear(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public CWarnClear(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) { @@ -63,9 +63,9 @@ namespace SharedLibrary.Commands } } - class Kick : Command + class CKick : Command { - public Kick(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public CKick(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) { @@ -77,9 +77,9 @@ namespace SharedLibrary.Commands } } - class Say : Command + class CSay : Command { - public Say(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public CSay(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) { @@ -87,16 +87,19 @@ namespace SharedLibrary.Commands } } - class TempBan : Command + class CTempBan : Command { - public TempBan(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public CTempBan(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) { E.Target.lastOffense = SharedLibrary.Utilities.RemoveWords(E.Data, 1); String Message = E.Target.lastOffense; if (E.Origin.Level > E.Target.Level) + { await E.Target.TempBan(Message, E.Origin); + await E.Origin.Tell($"Successfully temp banned {E.Target.Name}"); + } else await E.Origin.Tell("You cannot temp ban " + E.Target.Name); } @@ -118,7 +121,7 @@ namespace SharedLibrary.Commands if (E.Origin.Level > E.Target.Level) { await E.Target.Ban(Message, E.Origin); - await E.Origin.Tell(String.Format("Sucessfully banned ^5{0} ^7({1})", E.Target.Name, E.Target.npID)); + await E.Origin.Tell(String.Format("Sucessfully banned ^5{0} ^7({1})", E.Target.Name, E.Target.NetworkID)); } else await E.Origin.Tell("You cannot ban " + E.Target.Name); @@ -132,7 +135,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { await E.Owner.Unban(E.Target); - await E.Origin.Tell($"Successfully unbanned {E.Target.Name}::{E.Target.npID}"); + await E.Origin.Tell($"Successfully unbanned {E.Target.Name}::{E.Target.NetworkID}"); } } @@ -142,7 +145,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { - String You = String.Format("{0} [^3#{1}^7] {2} [^3@{3}^7] [{4}^7] IP: {5}", E.Origin.Name, E.Origin.clientID, E.Origin.npID, E.Origin.databaseID, SharedLibrary.Utilities.levelToColor(E.Origin.Level), E.Origin.IP); + String You = String.Format("{0} [^3#{1}^7] {2} [^3@{3}^7] [{4}^7] IP: {5}", E.Origin.Name, E.Origin.ClientID, E.Origin.NetworkID, E.Origin.DatabaseID, SharedLibrary.Utilities.levelToColor(E.Origin.Level), E.Origin.IP); await E.Origin.Tell(You); } } @@ -163,9 +166,9 @@ namespace SharedLibrary.Commands continue; if (P.Masked) - playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(Player.Permission.User), P.clientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - Player.Permission.User.ToString().Length)); + playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(Player.Permission.User), P.ClientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - Player.Permission.User.ToString().Length)); else - playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(P.Level), P.clientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length)); + playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.levelToColor(P.Level), P.ClientID, P.Name, SharedLibrary.Utilities.getSpaces(Player.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length)); if (count == 2 || E.Owner.getPlayers().Count == 1) { @@ -217,7 +220,10 @@ namespace SharedLibrary.Commands helpResponse.Append(" [^3" + C.Name + "^7] "); if (count >= 4) { - await E.Origin.Tell(helpResponse.ToString()); + if (E.Message[0] == '@') + await E.Owner.Broadcast(helpResponse.ToString()); + else + await E.Origin.Tell(helpResponse.ToString()); helpResponse = new StringBuilder(); count = 0; } @@ -288,7 +294,7 @@ namespace SharedLibrary.Commands { foreach (var player in server.getPlayers()) { - if (player != null && player.npID == E.Target.npID) + if (player != null && player.NetworkID == E.Target.NetworkID) { player.setLevel(newPerm); await E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm); @@ -341,7 +347,12 @@ namespace SharedLibrary.Commands { var P = E.Owner.Players[i]; if (P != null && P.Level > Player.Permission.Flagged && !P.Masked) - await E.Origin.Tell(String.Format("[^3{0}^7] {1}", Utilities.levelToColor(P.Level), P.Name)); + { + if (E.Message[0] == '@') + await E.Owner.Broadcast(String.Format("[^3{0}^7] {1}", Utilities.levelToColor(P.Level), P.Name)); + else + await E.Origin.Tell(String.Format("[^3{0}^7] {1}", Utilities.levelToColor(P.Level), P.Name)); + } } } } @@ -386,7 +397,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); } } @@ -431,7 +442,7 @@ namespace SharedLibrary.Commands if (Current != null) { - String mesg = String.Format("^1{0} ^7now goes by ^5{1}^7 [^3{2}^7]", lookingFor, Current.Name, Current.databaseID); + String mesg = String.Format("^1{0} ^7now goes by ^5{1}^7 [^3{2}^7]", lookingFor, Current.Name, Current.DatabaseID); await E.Origin.Tell(mesg); } } @@ -445,11 +456,22 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { if (E.Owner.rules.Count < 1) - await E.Origin.Tell("The server onwer has not set any rules."); + { + if (E.Message.IsBroadcastCommand()) + await E.Owner.Broadcast("The server owner has not set any rules."); + else + await E.Origin.Tell("The server owner has not set any rules."); + } + else { foreach (String r in E.Owner.rules) - await E.Origin.Tell("- " + r); + { + if (E.Message.IsBroadcastCommand()) + await E.Owner.Broadcast("- " + r); + else + await E.Origin.Tell("- " + r); + } } } } @@ -479,9 +501,9 @@ namespace SharedLibrary.Commands } } - class Flag : Command + class CFlag : Command { - public Flag(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public CFlag(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) { @@ -499,7 +521,9 @@ namespace SharedLibrary.Commands else { + E.Data = Utilities.RemoveWords(E.Data, 1); 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); } @@ -513,7 +537,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { - if (E.Owner.Reports.Find(x => (x.Origin == E.Origin && x.Target.npID == E.Target.npID)) != null) + if (E.Owner.Reports.Find(x => (x.Origin == E.Origin && x.Target.NetworkID == E.Target.NetworkID)) != null) { await E.Origin.Tell("You have already reported this player"); return; @@ -606,7 +630,7 @@ namespace SharedLibrary.Commands return; } - Player Banner = E.Owner.Manager.GetClientDatabase().GetPlayer(BannedPenalty.bannedByID, -1); + Player Banner = E.Owner.Manager.GetClientDatabase().GetPlayer(BannedPenalty.PenaltyOriginID, -1); if (Banner == null) { @@ -624,7 +648,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { - E.Target.Alias = E.Owner.Manager.GetAliasesDatabase().GetPlayerAliases(E.Target.databaseID); + E.Target.Alias = E.Owner.Manager.GetAliasesDatabase().GetPlayerAliases(E.Target.DatabaseID); if (E.Target.Alias == null) { @@ -675,7 +699,7 @@ namespace SharedLibrary.Commands public override async Task ExecuteAsync(Event E) { - await E.Origin.currentServer.ExecuteCommandAsync(E.Data.Trim()); + await E.Owner.ExecuteCommandAsync(E.Data.Trim()); await E.Origin.Tell("Successfuly sent RCON command!"); } } diff --git a/SharedLibrary/Database.cs b/SharedLibrary/Database.cs index d616eb2c0..bbbb0e454 100644 --- a/SharedLibrary/Database.cs +++ b/SharedLibrary/Database.cs @@ -440,7 +440,7 @@ namespace SharedLibrary public List GetClientPenalties(Player P) { List ClientPenalties = new List(); - String Query = $"SELECT * FROM `BANS` WHERE `npID` = '{P.npID}' OR `IP` = '{P.IP}'"; + String Query = $"SELECT * FROM `BANS` WHERE `npID` = '{P.NetworkID}' OR `IP` = '{P.IP}'"; DataTable Result = GetDataTable(Query); foreach (DataRow Row in Result.Rows) @@ -509,7 +509,7 @@ namespace SharedLibrary Dictionary newPlayer = new Dictionary { { "Name", Utilities.removeNastyChars(P.Name) }, - { "npID", P.npID }, + { "npID", P.NetworkID }, { "Level", (int)P.Level }, { "LastOffense", "" }, { "Connections", 1 }, @@ -527,7 +527,7 @@ namespace SharedLibrary Dictionary updatedPlayer = new Dictionary { { "Name", P.Name }, - { "npID", P.npID }, + { "npID", P.NetworkID }, { "Level", (int)P.Level }, { "LastOffense", P.lastOffense }, { "Connections", P.Connections }, @@ -536,7 +536,7 @@ namespace SharedLibrary { "UID", P.UID }, { "Masked", Convert.ToInt32(P.Masked) } }; - Update("CLIENTS", updatedPlayer, new KeyValuePair("npID", P.npID)); + Update("CLIENTS", updatedPlayer, new KeyValuePair("npID", P.NetworkID)); } @@ -546,8 +546,8 @@ namespace SharedLibrary Dictionary newBan = new Dictionary { { "Reason", Utilities.removeNastyChars(B.Reason) }, - { "npID", B.npID }, - { "bannedByID", B.bannedByID }, + { "npID", B.OffenderID }, + { "bannedByID", B.PenaltyOriginID }, { "IP", B.IP }, { "TIME", Utilities.DateTimeSQLite(DateTime.Now) }, { "TYPE", B.BType } diff --git a/SharedLibrary/Event.cs b/SharedLibrary/Event.cs index 9ef2130cb..4e3f6241e 100644 --- a/SharedLibrary/Event.cs +++ b/SharedLibrary/Event.cs @@ -125,7 +125,7 @@ namespace SharedLibrary { Regex rgx = new Regex("[^a-zA-Z0-9 -! -_]"); string message = rgx.Replace(line[4], ""); - return new Event(GType.Say, Utilities.removeNastyChars(message), SV.clientFromEventLine(line, 2), null, SV); + return new Event(GType.Say, Utilities.removeNastyChars(message), SV.clientFromEventLine(line, 2), null, SV) { Message = Utilities.removeNastyChars(message) }; } if (eventType == ":") @@ -149,6 +149,7 @@ namespace SharedLibrary public GType Type; public string Data; // Data is usually the message sent by player + public string Message; public Player Origin; public Player Target; public Server Owner; diff --git a/SharedLibrary/Interfaces/IManager.cs b/SharedLibrary/Interfaces/IManager.cs index 74725bee0..e56afa0bb 100644 --- a/SharedLibrary/Interfaces/IManager.cs +++ b/SharedLibrary/Interfaces/IManager.cs @@ -17,5 +17,6 @@ namespace SharedLibrary.Interfaces IPenaltyList GetClientPenalties(); ClientsDB GetClientDatabase(); AliasesDB GetAliasesDatabase(); + IList GetMessageTokens(); } } diff --git a/SharedLibrary/MessageToken.cs b/SharedLibrary/MessageToken.cs new file mode 100644 index 000000000..718e23460 --- /dev/null +++ b/SharedLibrary/MessageToken.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SharedLibrary +{ + public class MessageToken + { + public string Name { get; private set; } + Func Value; + public MessageToken(string Name, Func Value) + { + this.Name = Name; + this.Value = Value; + } + + public override string ToString() + { + return Value().ToString(); + } + } +} diff --git a/SharedLibrary/Penalty.cs b/SharedLibrary/Penalty.cs index ac5b1a33f..690645ec9 100644 --- a/SharedLibrary/Penalty.cs +++ b/SharedLibrary/Penalty.cs @@ -10,8 +10,8 @@ namespace SharedLibrary public Penalty(Type BType, String Reas, String TargID, String From, DateTime time, String ip) { Reason = Reas.Replace("!",""); - npID = TargID; - bannedByID = From; + OffenderID = TargID; + PenaltyOriginID = From; When = time; IP = ip; this.BType = BType; @@ -24,15 +24,17 @@ namespace SharedLibrary public enum Type { + Report, Warning, + Flag, Kick, TempBan, Ban } public String Reason { get; private set; } - public String npID { get; private set; } - public String bannedByID { get; private set; } + public String OffenderID { get; private set; } + public String PenaltyOriginID { get; private set; } public DateTime When { get; private set; } public String IP { get; private set; } public Type BType { get; private set; } diff --git a/SharedLibrary/Player.cs b/SharedLibrary/Player.cs index 2fb283745..4d56e9da5 100644 --- a/SharedLibrary/Player.cs +++ b/SharedLibrary/Player.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; using System.Linq; using System.Threading.Tasks; @@ -38,7 +37,7 @@ namespace SharedLibrary public override bool Equals(object obj) { - return ((Player)obj).npID == this.npID; + return ((Player)obj).NetworkID == NetworkID; } public override int GetHashCode() @@ -49,8 +48,8 @@ namespace SharedLibrary public Player(string n, string id, int num, int l) { Name = n; - npID = id; - clientID = num; + NetworkID = id; + ClientID = num; Level = (Player.Permission)l; lastOffense = String.Empty; Connections = 0; @@ -64,8 +63,8 @@ namespace SharedLibrary public Player(string n, string id, int num, String I) { Name = n; - npID = id; - clientID = num; + NetworkID = id; + ClientID = num; IP = I; LastConnection = DateTime.Now; } @@ -73,20 +72,20 @@ namespace SharedLibrary public Player(String n, String id, Player.Permission P, String I, String UID) { Name = n; - npID = id; + NetworkID = id; Level = P; IP = I; - clientID = -1; + ClientID = -1; this.UID = UID; } public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2) { Name = n; - npID = id; - clientID = num; + NetworkID = id; + ClientID = num; Level = l; - databaseID = cind; + DatabaseID = cind; if (lo == null) lastOffense = String.Empty; else @@ -101,10 +100,10 @@ namespace SharedLibrary public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2, DateTime LC, string UID, bool masked) { Name = n; - npID = id; - clientID = num; + NetworkID = id; + ClientID = num; Level = l; - databaseID = cind; + DatabaseID = cind; if (lo == null) lastOffense = String.Empty; else @@ -118,12 +117,9 @@ namespace SharedLibrary Masked = masked; } - public bool registerUID(String UID) + public override string ToString() { - if (UID.Length > 5) - this.UID = UID; - - return this.UID == UID; + return $"{Name}::{NetworkID}"; } public String getLastConnection() @@ -142,7 +138,7 @@ namespace SharedLibrary IP = I; } - public void setLevel(Player.Permission Perm) + public void setLevel(Permission Perm) { Level = Perm; } @@ -173,16 +169,14 @@ namespace SharedLibrary } public String Name { get; private set; } - public string npID { get; private set; } - public int clientID { get; private set; } - public Player.Permission Level { get; private set; } - public int databaseID { get; private set; } + public string NetworkID { get; private set; } + public int ClientID { get; private set; } + public Permission Level { get; private set; } + public int DatabaseID { get; private set; } public int Connections { get; set; } public String IP { get; private set; } public String UID { get; private set; } public DateTime LastConnection { get; private set; } - public Server currentServer { get; private set; } - public int Ping; public Event lastEvent; diff --git a/SharedLibrary/Server.cs b/SharedLibrary/Server.cs index 0fd3668f3..22386dc09 100644 --- a/SharedLibrary/Server.cs +++ b/SharedLibrary/Server.cs @@ -25,9 +25,7 @@ namespace SharedLibrary Players = new List(new Player[18]); events = new Queue(); - Macros = new Dictionary(); Reports = new List(); - statusPlayers = new Dictionary(); playerHistory = new Queue(); chatHistory = new List(); lastWebChat = DateTime.Now; @@ -44,10 +42,10 @@ namespace SharedLibrary if (owner == null) commands.Add(new Owner("owner", "claim ownership of the server", "owner", Player.Permission.User, 0, false)); - commands.Add(new Quit("quit", "quit IW4MAdmin", "q", Player.Permission.Owner, 0, false)); - commands.Add(new Kick("kick", "kick a player by name. syntax: !kick .", "k", Player.Permission.Trusted, 2, true)); - commands.Add(new Say("say", "broadcast message to all players. syntax: !say .", "s", Player.Permission.Moderator, 1, false)); - commands.Add(new TempBan("tempban", "temporarily ban a player for 1 hour. syntax: !tempban .", "tb", Player.Permission.Moderator, 2, true)); + 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)); + commands.Add(new CSay("say", "broadcast message to all players. syntax: !say .", "s", Player.Permission.Moderator, 1, false)); + commands.Add(new CTempBan("tempban", "temporarily ban a player for 1 hour. syntax: !tempban .", "tb", Player.Permission.Moderator, 2, true)); commands.Add(new CBan("ban", "permanently ban a player from the server. syntax: !ban ", "b", Player.Permission.SeniorAdmin, 2, true)); commands.Add(new CWhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false)); commands.Add(new CList("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false)); @@ -57,15 +55,15 @@ namespace SharedLibrary commands.Add(new CSetLevel("setlevel", "set player to specified administration level. syntax: !setlevel .", "sl", Player.Permission.Owner, 2, true)); commands.Add(new CUsage("usage", "get current application memory usage. syntax: !usage.", "us", Player.Permission.Moderator, 0, false)); commands.Add(new CUptime("uptime", "get current application running time. syntax: !uptime.", "up", Player.Permission.Moderator, 0, false)); - commands.Add(new Warn("warn", "warn player for infringing rules syntax: !warn .", "w", Player.Permission.Trusted, 2, true)); - commands.Add(new WarnClear("warnclear", "remove all warning for a player syntax: !warnclear .", "wc", Player.Permission.Trusted, 1, true)); + commands.Add(new Cwarn("warn", "warn player for infringing rules syntax: !warn .", "w", Player.Permission.Trusted, 2, true)); + commands.Add(new CWarnClear("warnclear", "remove all warning for a player syntax: !warnclear .", "wc", Player.Permission.Trusted, 1, true)); commands.Add(new CUnban("unban", "unban player by database id. syntax: !unban @.", "ub", Player.Permission.SeniorAdmin, 1, true)); commands.Add(new CListAdmins("admins", "list currently connected admins. syntax: !admins.", "a", Player.Permission.User, 0, false)); commands.Add(new CLoadMap("map", "change to specified map. syntax: !map", "m", Player.Permission.Administrator, 1, false)); commands.Add(new CFindPlayer("find", "find player in database. syntax: !find ", "f", Player.Permission.SeniorAdmin, 1, false)); commands.Add(new CListRules("rules", "list server rules. syntax: !rules", "r", Player.Permission.User, 0, false)); commands.Add(new CPrivateMessage("privatemessage", "send message to other player. syntax: !pm ", "pm", Player.Permission.User, 2, true)); - commands.Add(new Flag("flag", "flag a suspicious player and announce to admins on join . syntax !flag :", "flag", Player.Permission.Moderator, 1, true)); + commands.Add(new CFlag("flag", "flag a suspicious player and announce to admins on join . syntax !flag :", "flag", Player.Permission.Moderator, 2, true)); commands.Add(new CReport("report", "report a player for suspicious behaivor. syntax !report ", "rep", Player.Permission.User, 2, true)); commands.Add(new CListReports("reports", "get most recent reports. syntax !reports", "reports", Player.Permission.Moderator, 0, false)); commands.Add(new CMask("mask", "hide your online presence from online admin list. syntax: !mask", "mask", Player.Permission.Administrator, 0, false)); @@ -234,10 +232,11 @@ namespace SharedLibrary public async Task Tell(String Message, Player Target) { #if DEBUG - return; + if (!Target.lastEvent.Remote) + return; #endif - if (Target.clientID > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console && !Target.lastEvent.Remote) - await this.ExecuteCommandAsync($"tellraw {Target.clientID} {Message}^7"); + if (Target.ClientID > -1 && Message.Length > 0 && Target.Level != Player.Permission.Console && !Target.lastEvent.Remote) + await this.ExecuteCommandAsync($"tellraw {Target.ClientID} {Message}^7"); if (Target.Level == Player.Permission.Console) { @@ -456,24 +455,15 @@ namespace SharedLibrary protected DateTime lastPoll; protected int nextMessage; - protected Dictionary Macros; protected DateTime lastWebChat; public string Password { get; private set; } public int Handle { get; private set; } protected int PID; protected IFile logFile; - // Will probably move this later - public Dictionary statusPlayers; - public bool isRunning; - // Log stuff protected String Mod; - // Databases - //public ClientsDB clientDB; - //public AliasesDB aliasDB; - //Remote public Queue commandResult = new Queue(); } diff --git a/SharedLibrary/SharedLibrary.csproj b/SharedLibrary/SharedLibrary.csproj index 2aa5b492a..50076431a 100644 --- a/SharedLibrary/SharedLibrary.csproj +++ b/SharedLibrary/SharedLibrary.csproj @@ -76,6 +76,7 @@ + diff --git a/SharedLibrary/Utilities.cs b/SharedLibrary/Utilities.cs index d2676f02a..869ab0476 100644 --- a/SharedLibrary/Utilities.cs +++ b/SharedLibrary/Utilities.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Text; using System.Text.RegularExpressions; +using System.Linq; using System.Collections.Generic; namespace SharedLibrary @@ -120,27 +121,28 @@ namespace SharedLibrary } } - public static String LoadMacro(Dictionary Dict, String str) + public static String ProcessMessageToken(IList tokens, String str) { - MatchCollection Found = Regex.Matches(str, @"\{\{[A-Z]+\}\}", RegexOptions.IgnoreCase); - foreach (Match M in Found) + MatchCollection RegexMatches = Regex.Matches(str, @"\{\{[A-Z]+\}\}", RegexOptions.IgnoreCase); + foreach (Match M in RegexMatches) { String Match = M.Value; String Identifier = M.Value.Substring(2, M.Length - 4); - Dict.TryGetValue(Identifier, out object foundVal); - String Replacement; - if (foundVal != null) - Replacement = foundVal.ToString(); - else - Replacement = ""; + var found = tokens.FirstOrDefault(t => t.Name.ToLower() == Identifier.ToLower()); - str = str.Replace(Match, Replacement); + if (found != null) + str = str.Replace(Match, found.ToString()); } return str; } + public static bool IsBroadcastCommand(this string str) + { + return str[0] == '@'; + } + ///

/// Get the full gametype name /// diff --git a/Stats Plugin/Plugin.cs b/Stats Plugin/Plugin.cs index 8ba5c728f..92e980cad 100644 --- a/Stats Plugin/Plugin.cs +++ b/Stats Plugin/Plugin.cs @@ -20,27 +20,34 @@ 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); } - await E.Origin.Tell(statLine); + if (E.Message.IsBroadcastCommand()) + { + string name = E.Target == null ? E.Origin.Name : E.Target.Name; + await E.Owner.Broadcast($"Stats for ^5{name}^7"); + await E.Owner.Broadcast(statLine); + } + else + await E.Origin.Tell(statLine); } } public class CViewTopStats : Command { - public CViewTopStats() : base("topstats", "view the top 5 players on this server. syntax !topstats", "!ts", Player.Permission.User, 0, false) { } + public CViewTopStats() : base("topstats", "view the top 5 players on this server. syntax !topstats", "ts", Player.Permission.User, 0, false) { } public override async Task ExecuteAsync(Event E) { - List> pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.topStats(); + List> pStats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetTopStats(); StringBuilder msgBlder = new StringBuilder(); await E.Origin.Tell("^5--Top Players--"); @@ -54,6 +61,23 @@ namespace StatsPlugin } } + public class CResetStats : Command + { + public CResetStats() : base("resetstats", "reset your stats to factory-new, !syntax !resetstats", "rs", Player.Permission.User, 0, false) { } + + public override async Task ExecuteAsync(Event E) + { + var stats = Stats.statLists.Find(x => x.Port == E.Owner.getPort()).playerStats.GetStats(E.Origin); + stats.Deaths = 0; + stats.Kills = 0; + stats.scorePerMinute = 0.0; + stats.Skill = 0; + stats.KDR = 0.0; + 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"); + } + } + /// /// Each server runs from the same plugin ( for easier reloading and reduced memory usage ). /// So, to have multiple stat tracking, we must store a stat struct for each server @@ -89,7 +113,7 @@ namespace StatsPlugin public float Version { - get { return 1f; } + get { return 1.1f; } } public string Author @@ -117,6 +141,8 @@ namespace StatsPlugin if (E.Type == Event.GType.Start) { statLists.Add(new StatTracking(S.getPort())); + S.Manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", statLists.Find(c => c.Port == S.getPort()).playerStats.GetTotalPlaytime().ToString("#,##0").ToString)); + S.Manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", statLists.Find(c => c.Port == S.getPort()).playerStats.GetTotalKills().ToString("#,##0").ToString)); } if (E.Type == Event.GType.Stop) @@ -126,10 +152,10 @@ namespace StatsPlugin 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); - if (checkForTrusted.playTime >= 4320 && E.Origin.Level < Player.Permission.Trusted) + 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.Owner.Manager.GetClientDatabase().UpdatePlayer(E.Origin); @@ -146,19 +172,19 @@ 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.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)); } } if (E.Type == Event.GType.Disconnect) { - 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); + 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); } if (E.Type == Event.GType.Kill) @@ -168,14 +194,14 @@ namespace StatsPlugin Player Killer = E.Origin; StatTracking curServer = statLists.Find(x => x.Port == S.getPort()); - PlayerStats killerStats = curServer.playerStats.getStats(Killer); + PlayerStats killerStats = curServer.playerStats.GetStats(Killer); - curServer.lastKill[E.Origin.clientID] = DateTime.Now; - curServer.Kills[E.Origin.clientID]++; + curServer.lastKill[E.Origin.ClientID] = DateTime.Now; + curServer.Kills[E.Origin.ClientID]++; - if ((curServer.lastKill[E.Origin.clientID] - DateTime.Now).TotalSeconds > 60) - curServer.inactiveMinutes[E.Origin.clientID]++; + if ((curServer.lastKill[E.Origin.ClientID] - DateTime.Now).TotalSeconds > 60) + curServer.inactiveMinutes[E.Origin.ClientID]++; killerStats.Kills++; @@ -184,12 +210,12 @@ namespace StatsPlugin else killerStats.KDR = Math.Round((double)killerStats.Kills / (double)killerStats.Deaths, 2); - curServer.playerStats.updateStats(Killer, killerStats); + curServer.playerStats.UpdateStats(Killer, killerStats); - curServer.killStreaks[Killer.clientID] += 1; - curServer.deathStreaks[Killer.clientID] = 0; + curServer.killStreaks[Killer.ClientID] += 1; + curServer.deathStreaks[Killer.ClientID] = 0; - await Killer.Tell(messageOnStreak(curServer.killStreaks[Killer.clientID], curServer.deathStreaks[Killer.clientID])); + await Killer.Tell(MessageOnStreak(curServer.killStreaks[Killer.ClientID], curServer.deathStreaks[Killer.ClientID])); } if (E.Type == Event.GType.Death) @@ -199,61 +225,63 @@ namespace StatsPlugin Player Victim = E.Origin; StatTracking curServer = statLists.Find(x => x.Port == S.getPort()); - PlayerStats victimStats = curServer.playerStats.getStats(Victim); + PlayerStats victimStats = curServer.playerStats.GetStats(Victim); victimStats.Deaths++; victimStats.KDR = Math.Round((double)victimStats.Kills / (double)victimStats.Deaths, 2); - curServer.playerStats.updateStats(Victim, victimStats); + curServer.playerStats.UpdateStats(Victim, victimStats); - curServer.deathStreaks[Victim.clientID] += 1; - curServer.killStreaks[Victim.clientID] = 0; + curServer.deathStreaks[Victim.ClientID] += 1; + curServer.killStreaks[Victim.ClientID] = 0; - await Victim.Tell(messageOnStreak(curServer.killStreaks[Victim.clientID], curServer.deathStreaks[Victim.clientID])); + await Victim.Tell(MessageOnStreak(curServer.killStreaks[Victim.ClientID], curServer.deathStreaks[Victim.ClientID])); } } - private void calculateAndSaveSkill(Player P, StatTracking curServer) + private void CalculateAndSaveSkill(Player P, StatTracking curServer) { if (P == null) return; - PlayerStats disconnectStats = curServer.playerStats.getStats(P); - if (curServer.Kills[P.clientID] == 0) + PlayerStats DisconnectingPlayerStats = curServer.playerStats.GetStats(P); + if (curServer.Kills[P.ClientID] == 0) return; - else if (curServer.lastKill[P.clientID] > curServer.connectionTime[P.clientID]) - curServer.inactiveMinutes[P.clientID] += (int)(DateTime.Now - curServer.lastKill[P.clientID]).TotalMinutes; + else if (curServer.lastKill[P.ClientID] > curServer.connectionTime[P.ClientID]) + curServer.inactiveMinutes[P.ClientID] += (int)(DateTime.Now - curServer.lastKill[P.ClientID]).TotalMinutes; - int newPlayTime = (int)(DateTime.Now - curServer.connectionTime[P.clientID]).TotalMinutes - curServer.inactiveMinutes[P.clientID]; + int newPlayTime = (int)(DateTime.Now - curServer.connectionTime[P.ClientID]).TotalMinutes - curServer.inactiveMinutes[P.ClientID]; if (newPlayTime < 2) return; - double newSPM = curServer.Kills[P.clientID] * 50 / Math.Max(1, newPlayTime); - double kdrWeight = Math.Round(Math.Pow(disconnectStats.KDR, 2 / Math.E), 3); - double Multiplier; + // calculate the players Score Per Minute for the current session + double SessionSPM = curServer.Kills[P.ClientID] * 100 / Math.Max(1, newPlayTime); + // calculate how much the KDR should way + // 0.81829 is a Eddie-Generated number that weights the KDR nicely + double KDRWeight = Math.Round(Math.Pow(DisconnectingPlayerStats.KDR, 1.637 / Math.E), 3); + double SPMWeightAgainstAverage; - if (disconnectStats.scorePerMinute == 1) - Multiplier = 1; - else - Multiplier = newSPM / disconnectStats.scorePerMinute; + // if no SPM, weight is 1 else the weight is the current sessions spm / lifetime average score per minute + SPMWeightAgainstAverage = (DisconnectingPlayerStats.scorePerMinute == 1) ? 1 : SessionSPM / DisconnectingPlayerStats.scorePerMinute; - double scoreWeight = (newSPM * (newPlayTime / disconnectStats.playTime)); - double newSkillFactor = Multiplier * scoreWeight; + // calculate the weight of the new play time againmst lifetime playtime + // + double SPMAgainstPlayWeight = newPlayTime / Math.Min(600, DisconnectingPlayerStats.TotalPlayTime); + // calculate the new weight against average times the weight against play time + double newSkillFactor = SPMWeightAgainstAverage * SPMAgainstPlayWeight; - if (Multiplier >= 1) - disconnectStats.scorePerMinute += newSkillFactor; - else - disconnectStats.scorePerMinute -= (scoreWeight - newSkillFactor); + // if the weight is greater than 1, add, else subtract + DisconnectingPlayerStats.scorePerMinute += (SPMWeightAgainstAverage >= 1) ? newSkillFactor : -newSkillFactor; - disconnectStats.Skill = disconnectStats.scorePerMinute * kdrWeight / 10; - disconnectStats.playTime += newPlayTime; + DisconnectingPlayerStats.Skill = DisconnectingPlayerStats.scorePerMinute * KDRWeight / 10; + DisconnectingPlayerStats.TotalPlayTime += newPlayTime; - curServer.playerStats.updateStats(P, disconnectStats); + curServer.playerStats.UpdateStats(P, DisconnectingPlayerStats); } - private void resetCounters(int cID, int serverPort) + private void ResetCounters(int cID, int serverPort) { StatTracking selectedPlayers = statLists.Find(x => x.Port == serverPort); @@ -264,7 +292,7 @@ namespace StatsPlugin selectedPlayers.killStreaks[cID] = 0; } - private String messageOnStreak(int killStreak, int deathStreak) + private String MessageOnStreak(int killStreak, int deathStreak) { String Message = ""; switch (killStreak) @@ -304,24 +332,24 @@ namespace StatsPlugin } } - public void addPlayer(Player P) + public void AddPlayer(Player P) { - Dictionary newPlayer = new Dictionary(); - - newPlayer.Add("npID", P.npID); - newPlayer.Add("KILLS", 0); - newPlayer.Add("DEATHS", 0); - newPlayer.Add("KDR", 0.0); - newPlayer.Add("SKILL", 1.0); - newPlayer.Add("SPM", 1.0); - newPlayer.Add("PLAYTIME", 1.0); - + Dictionary newPlayer = new Dictionary + { + { "npID", P.NetworkID }, + { "KILLS", 0 }, + { "DEATHS", 0 }, + { "KDR", 0.0 }, + { "SKILL", 1.0 }, + { "SPM", 1.0 }, + { "PLAYTIME", 1.0 } + }; Insert("STATS", newPlayer); } - public PlayerStats getStats(Player P) + public PlayerStats GetStats(Player P) { - DataTable Result = GetDataTable("STATS", new KeyValuePair("npID", P.npID)); + DataTable Result = GetDataTable("STATS", new KeyValuePair("npID", P.NetworkID)); if (Result != null && Result.Rows.Count > 0) { @@ -338,26 +366,38 @@ namespace StatsPlugin else { - addPlayer(P); - return getStats(P); + AddPlayer(P); + return GetStats(P); } } - public void updateStats(Player P, PlayerStats S) + public int GetTotalKills() { - Dictionary updatedPlayer = new Dictionary(); - - updatedPlayer.Add("KILLS", S.Kills); - updatedPlayer.Add("DEATHS", S.Deaths); - updatedPlayer.Add("KDR", Math.Round(S.KDR, 2)); - updatedPlayer.Add("SKILL", Math.Round(S.Skill, 1)); - updatedPlayer.Add("SPM", Math.Round(S.scorePerMinute, 1)); - updatedPlayer.Add("PLAYTIME", S.playTime); - - Update("STATS", updatedPlayer, new KeyValuePair("npID", P.npID)); + var Result = GetDataTable("SELECT SUM(KILLS) FROM STATS"); + return Result.Rows[0][0].GetType() == typeof(DBNull) ? 0 : Convert.ToInt32(Result.Rows[0][0]); } - public List> topStats() + public int GetTotalPlaytime() + { + var Result = GetDataTable("SELECT SUM(PLAYTIME) FROM STATS"); + return Result.Rows[0][0].GetType() == typeof(DBNull) ? 0 : Convert.ToInt32(Result.Rows[0][0]) / 60; + } + + public void UpdateStats(Player P, PlayerStats S) + { + Dictionary updatedPlayer = new Dictionary + { + { "KILLS", S.Kills }, + { "DEATHS", S.Deaths }, + { "KDR", Math.Round(S.KDR, 2) }, + { "SKILL", Math.Round(S.Skill, 1) }, + { "SPM", Math.Round(S.scorePerMinute, 1) }, + { "PLAYTIME", S.TotalPlayTime } + }; + Update("STATS", updatedPlayer, new KeyValuePair("npID", P.NetworkID)); + } + + public List> GetTopStats() { String Query = String.Format("SELECT * FROM STATS WHERE SKILL > 0 AND KDR < '{0}' AND KILLS > '{1}' AND PLAYTIME > '{2}' ORDER BY SKILL DESC LIMIT '{3}'", 10, 150, 60, 5); DataTable Result = GetDataTable(Query); @@ -392,7 +432,7 @@ namespace StatsPlugin KDR = DR; Skill = S; scorePerMinute = sc; - playTime = P; + TotalPlayTime = P; } public int Kills; @@ -400,6 +440,6 @@ namespace StatsPlugin public double KDR; public double Skill; public double scorePerMinute; - public int playTime; + public int TotalPlayTime; } } \ No newline at end of file diff --git a/Votemap Plugin/Plugin.cs b/Votemap Plugin/Plugin.cs index 921547056..25f062614 100644 --- a/Votemap Plugin/Plugin.cs +++ b/Votemap Plugin/Plugin.cs @@ -31,7 +31,7 @@ namespace Votemap_Plugin // we only want to allow a vote during a vote session if (voting.voteInSession) { - if (voting.hasVoted(E.Origin.npID)) + if (voting.hasVoted(E.Origin.NetworkID)) await E.Origin.Tell("You have already voted. Use ^5!vc ^7to ^5cancel ^7your vote"); else { @@ -42,7 +42,7 @@ namespace Votemap_Plugin await E.Origin.Tell("^1" + E.Data + " is not a recognized map"); else { - voting.castVote(E.Origin.npID, votedMap); + voting.castVote(E.Origin.NetworkID, votedMap); await E.Origin.Tell("You voted for ^5" + votedMap.Alias); } } @@ -63,9 +63,9 @@ namespace Votemap_Plugin if (voting.voteInSession) { - if (voting.hasVoted(E.Origin.npID)) + if (voting.hasVoted(E.Origin.NetworkID)) { - voting.cancelVote(E.Origin.npID); + voting.cancelVote(E.Origin.NetworkID); await E.Origin.Tell("Vote cancelled"); }