diff --git a/Admin/Command.cs b/Admin/Command.cs index b21cc794..a191a0e6 100644 --- a/Admin/Command.cs +++ b/Admin/Command.cs @@ -203,7 +203,7 @@ namespace IW4MAdmin public override void Execute(Event E) { - String You = String.Format("You are {0} at client spot {1} with xuid {2} and ID {5}. You have connected {3} times and are currently ranked {4}", E.Origin.getName(), E.Origin.getClientNum(), E.Origin.getID(), E.Origin.getConnections(), E.Origin.getLevel(), E.Origin.getDBID()); + String You = String.Format("{0} [^3{1}^7] {{2}} {{3}} [{4}^7] IP: {5}", E.Origin.getName(), E.Origin.getClientNum(), E.Origin.getID(), Utilities.levelToColor(E.Origin.getLevel()), E.Origin.getDBID(), E.Origin.getIP()); E.Origin.Tell(You); } @@ -412,32 +412,51 @@ namespace IW4MAdmin public override void Execute(Event E) { var db_players = E.Owner.clientDB.findPlayers(E.Data.Trim()); + if (db_players == null) { E.Origin.Tell("No players found"); return; } - - foreach (Player P in db_players) { String mesg; - var db_aliases = E.Owner.aliasDB.getPlayer(P.getDBID()); + P.Alias = E.Owner.aliasDB.getPlayer(P.getDBID()); if (P.getLevel() == Player.Permission.Banned) mesg = String.Format("[^3{0}^7] [^3@{1}^7] - {2} [{3}^7] - {4}", P.getName(), P.getDBID(), P.getID(), Utilities.levelToColor(P.getLevel()), P.getLastO()); else mesg = String.Format("[^3{0}^7] [^3@{1}^7] - {2} [{3}^7]", P.getName(), P.getDBID(), P.getID(), Utilities.levelToColor(P.getLevel())); - E.Origin.Tell(mesg); - if (db_aliases != null) - { - mesg = "Aliases: "; - foreach (String S in db_aliases.getNames()) - mesg += S + ','; - } E.Origin.Tell(mesg); + + if (P.Alias == null) + continue; + + if (P.Alias.getNames() != null) + { + mesg = "Aliases: "; + foreach (String S in P.Alias.getNames()) + { + if (S != String.Empty) + mesg += S + " | "; + } + E.Origin.Tell(mesg); + } + + if (P.Alias.getIPS() != null) + { + mesg = "IPs: "; + foreach (String IP in P.Alias.getIPS()) + { + if (IP.Split('.').Length > 3 && IP != String.Empty) + mesg += IP + " | "; + } + + E.Origin.Tell(mesg); + + } } } @@ -515,7 +534,6 @@ namespace IW4MAdmin { if (P != null) E.Origin.Tell(String.Format("^3{0}^7 - ^5{1} ^7KDR | ^5{2} ^7SKILL", P.getName(), P.stats.KDR, P.stats.Skill)); - } } else @@ -536,5 +554,106 @@ namespace IW4MAdmin } } + class Balance : Command + { + public Balance(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + public override void Execute(Event E) + { + E.Owner.RCON.addRCON(String.Format("admin_lastevent {0};{1}", "balance", E.Origin.getID())); //Let gsc do the magic + } + } + + class GoTo : Command + { + public GoTo(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + + public override void Execute(Event E) + { + E.Owner.RCON.addRCON(String.Format("admin_lastevent {0};{1};{2};{3}", "goto", E.Origin.getID(), E.Target.getName(), E.Data)); //Let gsc do the magic + } + } + + class Flag : Command + { + public Flag(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + + public override void Execute(Event E) + { + if (E.Target.getLevel() >= E.Origin.getLevel()) + { + E.Origin.Tell("You cannot flag " + E.Target.getName()); + return; + } + + if (E.Target.getLevel() == Player.Permission.Flagged) + { + E.Target.setLevel(Player.Permission.User); + E.Origin.Tell("You have ^5unflagged ^7" + E.Target.getName()); + } + + else + { + E.Target.setLevel(Player.Permission.Flagged); + E.Origin.Tell("You have ^5flagged ^7" + E.Target.getName()); + } + + E.Owner.clientDB.updatePlayer(E.Target); + } + } + + class _Report : Command + { + public _Report(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + + public override void Execute(Event E) + { + if (E.Target.getLevel() > E.Origin.getLevel()) + { + E.Origin.Tell("You cannot report " + E.Target.getName()); + return; + } + + E.Data = Utilities.removeWords(E.Data, 1); + E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data)); + E.Origin.Tell("Successfully reported " + E.Target.getName()); + + E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.getName(), E.Target.getName(), E.Data)); + } + } + + class Reports : Command + { + public Reports(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + + public override void Execute(Event E) + { + if (E.Owner.Reports.Count < 1) + { + E.Origin.Tell("No players reported yet."); + return; + } + + int count = E.Owner.Reports.Count - 1; + for (int i = 0; i <= count; i++) + { + if (count > 8) + i = count - 8; + Report R = E.Owner.Reports[i]; + E.Origin.Tell(String.Format("^5{0}^7->^1{1}^7: {2}", R.Origin.getName(), R.Target.getName(), R.Reason)); + } + } + } + + class _Tell : Command + { + public _Tell(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { } + + public override void Execute(Event E) + { + E.Data = Utilities.removeWords(E.Data, 1); + E.Owner.RCON.addRCON(String.Format("admin_lastevent tell;{0};{1};{2}", E.Origin.getID(), E.Target.getID(), E.Data)); + } + } } + \ No newline at end of file diff --git a/Admin/Database.cs b/Admin/Database.cs index a29c8445..218f5a84 100644 --- a/Admin/Database.cs +++ b/Admin/Database.cs @@ -152,9 +152,9 @@ namespace IW4MAdmin DataRow ResponseRow = Result.Rows[0]; - if (ResponseRow["IP"].ToString().Length < 2) - ResponseRow["IP"] = DateTime.Now.ToString(); // because aliases and backwards compatibility - + // if (ResponseRow["IP"].ToString().Length < 2) + // ResponseRow["IP"] = DateTime.Now.ToString(); // because aliases and backwards compatibility + return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"], ResponseRow["IP"].ToString()); } @@ -172,8 +172,8 @@ namespace IW4MAdmin { DataRow p = Result.Rows[0]; - if (p["IP"].ToString().Length < 2) - p["IP"] = DateTime.Now.ToString(); // because aliases and backwards compatibility + // if (p["IP"].ToString().Length < 2) + // p["IP"] = DateTime.Now.ToString(); // because aliases and backwards compatibility return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), Convert.ToInt32(p["Connections"]), p["IP"].ToString()); } @@ -231,8 +231,8 @@ namespace IW4MAdmin { if (Row["TIME"].ToString().Length < 2) //compatibility with my old database Row["TIME"] = DateTime.Now.ToString(); - if (Row["IP"].ToString().Length < 2) - Row["IP"] = DateTime.Now.ToString(); //because we don't have old ip's and don't want a messy alias + // if (Row["IP"].ToString().Length < 2) + // Row["IP"] = DateTime.Now.ToString(); //because we don't have old ip's and don't want a messy alias Bans.Add(new Ban(Row["Reason"].ToString(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString())); } diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj index 7a57e911..3ba02d14 100644 --- a/Admin/IW4M ADMIN.csproj +++ b/Admin/IW4M ADMIN.csproj @@ -29,7 +29,7 @@ true publish.htm 7 - 0.6.0.%2a + 0.7.0.%2a false true true @@ -106,6 +106,7 @@ Settings.settings + diff --git a/Admin/Log.cs b/Admin/Log.cs index 2471a321..f57ab434 100644 --- a/Admin/Log.cs +++ b/Admin/Log.cs @@ -14,16 +14,17 @@ namespace IW4MAdmin None, } - public Log(file logf, Level mode) + public Log(file logf, Level mode, int port) { logFile = logf; logMode = mode; + Port = port; } public void Write(String line, Level lv) { - String Line = String.Format("{1} - [{0}]: {2}", lv, getTime(), line); + String Line = String.Format("{1} - [{0}]: {2}", Port, getTime(), line); switch(logMode) { case Level.All: @@ -50,5 +51,6 @@ namespace IW4MAdmin private file logFile; private Level logMode; + private int Port; } } diff --git a/Admin/Main.cs b/Admin/Main.cs index 3406c4c5..d378a618 100644 --- a/Admin/Main.cs +++ b/Admin/Main.cs @@ -29,10 +29,11 @@ namespace IW4MAdmin foreach (Server IW4M in checkConfig()) { //Threading seems best here - Thread monitorThread = new Thread(new ThreadStart(IW4M.Monitor)); + Server SV = IW4M; + Thread monitorThread = new Thread(new ThreadStart(SV.Monitor)); monitorThread.Start(); - Utilities.Wait(0.3); - Console.WriteLine("Now monitoring " + IW4M.getName()); + Utilities.Wait(0.2); // give rcon a chance to respond + Console.WriteLine("Now monitoring " + SV.getName()); } Utilities.Wait(5); //Give them time to read an error before exiting diff --git a/Admin/Player.cs b/Admin/Player.cs index 5e28c93b..470beee2 100644 --- a/Admin/Player.cs +++ b/Admin/Player.cs @@ -72,12 +72,14 @@ namespace IW4MAdmin public void addName(String Name) { - Names += Names + ';'; + if (Name.Trim() != String.Empty && Name != null) + Names += ';' + Names; } public void addIP(String IP) { - IPS += IP + ';'; + if (IP.Trim() != String.Empty && IP != null) + IPS += ';' + IP; } private String Names; @@ -89,6 +91,7 @@ namespace IW4MAdmin { public enum Permission { + Flagged = -2, Banned = -1, User = 0, Moderator = 1, diff --git a/Admin/Report.cs b/Admin/Report.cs new file mode 100644 index 00000000..534b2b84 --- /dev/null +++ b/Admin/Report.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace IW4MAdmin +{ + class Report + { + public Report(Player T, Player O, String R) + { + Target = T; + Origin = O; + Reason = R; + } + + public Player Target { get; private set; } + public Player Origin { get; private set; } + public String Reason { get; private set; } + } +} \ No newline at end of file diff --git a/Admin/Server.cs b/Admin/Server.cs index aefc3d84..e68ee67d 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -22,9 +22,9 @@ namespace IW4MAdmin RCON = new RCON(this); logFile = new file("admin_" + port + ".log", true); #if DEBUG - Log = new Log(logFile, Log.Level.Debug); + Log = new Log(logFile, Log.Level.Debug, port); #else - Log = new Log(logFile, Log.Level.Production); + Log = new Log(logFile, Log.Level.Production, port); #endif players = new List(new Player[18]); clientDB = new ClientsDB("clients.rm"); @@ -35,6 +35,7 @@ namespace IW4MAdmin events = new Queue(); HB = new Heartbeat(this); Macros = new Dictionary(); + Reports = new List(); nextMessage = 0; initCommands(); initMacros(); @@ -112,13 +113,11 @@ namespace IW4MAdmin clientDB.addPlayer(P); Player New = clientDB.getPlayer(P.getID(), P.getClientNum()); statDB.addPlayer(New); - aliasDB.addPlayer(new Aliases(New.getDBID(), New.getName(), New.getIP())); } //messy way to prevent loss of last event Player NewPlayer = clientDB.getPlayer(P.getID(), P.getClientNum()); NewPlayer.stats = statDB.getStats(NewPlayer.getDBID()); - NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.getDBID()); if (NewPlayer.stats == null) //For safety { @@ -134,36 +133,40 @@ namespace IW4MAdmin if (players[NewPlayer.getClientNum()] == null) { bool updated = false; - while (!updated) + while (!updated) //Sometimes we get a issue when a player disconnects and it doesn't register { try { P.updateIP(IPS[P.getID()].Trim()); - updated = true; + + NewPlayer.updateIP(P.getIP()); Log.Write("Sucessfully updated " + NewPlayer.getName() + "'s IP to " + P.getIP(), Log.Level.Debug); + updated = true; } catch { - //Log.Write("Looks like the connecting player doesn't have an IP location assigned yet. Let's wait for next poll", Log.Level.Debug); - Utilities.Wait(1); + Log.Write("Waiting for " + P.getName() + "'s IP...", Log.Level.Debug); + Utilities.Wait(2); } } - if (NewPlayer.Alias == null) - { - aliasDB.addPlayer(new Aliases(NewPlayer.getDBID(), NewPlayer.getName(), P.getIP())); - } - - if (P.getName() != NewPlayer.getName()) + if (aliasDB.getPlayer(NewPlayer.getDBID()) == null) + aliasDB.addPlayer(new Aliases(NewPlayer.getDBID(), P.getName(), P.getIP())); + + NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.getDBID()); + + if ((NewPlayer.Alias.getNames().Find(m => m.Equals(P.getName()))) == null || NewPlayer.getName() == null || NewPlayer.getName() == String.Empty) { + Log.Write("Connecting player has new alias -- " + P.getName() + " previous was: " + NewPlayer.getName(), Log.Level.Debug); NewPlayer.updateName(P.getName()); NewPlayer.Alias.addName(P.getName()); aliasDB.updatePlayer(NewPlayer.Alias); } - if (P.getIP() != NewPlayer.getIP()) + if (NewPlayer.Alias.getIPS().Find(i => i.Equals(P.getIP())) == null || P.getIP() == null || P.getIP() == String.Empty) { + Log.Write("Connecting player has new IP - " + P.getIP(), Log.Level.Debug); NewPlayer.updateIP(P.getIP()); NewPlayer.Alias.addIP(P.getIP()); aliasDB.updatePlayer(NewPlayer.Alias); @@ -177,6 +180,7 @@ namespace IW4MAdmin { Log.Write("Banned client " + P.getName() + " trying to connect...", Log.Level.Debug); string Reason = String.Empty; + if (B != null) Reason = B.getReason(); else @@ -184,14 +188,23 @@ namespace IW4MAdmin String Message = "^1Player Kicked: ^7Previously Banned for ^5" + Reason; NewPlayer.Kick(Message); + + if (players[P.getClientNum()] != null) + players[P.getClientNum()] = null; + + return true; } players[NewPlayer.getClientNum()] = null; players[NewPlayer.getClientNum()] = NewPlayer; - +#if DEBUG == FALSE NewPlayer.Tell("Welcome ^5" + NewPlayer.getName() + " ^7this is your ^5" + Utilities.timesConnected(NewPlayer.getConnections()) + " ^7time connecting!"); +#endif Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); clientnum++; + + if (NewPlayer.getLevel() == Player.Permission.Flagged) + ToAdmins("^1NOTICE: ^7Flagged player ^5" + NewPlayer.getName() + "^7 has joined!"); } return true; @@ -324,14 +337,19 @@ namespace IW4MAdmin { foreach (Ban B in Bans) { - + if (B.getID().Length < 5 || B.getIP().Length < 5) + continue; + + if (B.getID() == null || C.getID() == null) + continue; + if (B.getID() == C.getID()) return B; - if (B.getIP() == null) + if (B.getIP() == null || C.getIP() == null) continue; - if (C.Alias.getIPS().Find(f => f.Contains(B.getIP())) != null) + if (C.Alias.getIPS().Find(f => f.Equals(B.getIP())) != null) return B; if (C.getIP() == B.getIP()) @@ -364,9 +382,13 @@ namespace IW4MAdmin int cNum = -1; int.TryParse(Args[0], out cNum); + if (C.getName() == "stats" && Args.Length == 1) + E.Target = E.Origin; + if (Args[0] == String.Empty) return C; + if (Args[0][0] == '@') // user specifying target by database ID { int dbID = -1; @@ -456,7 +478,7 @@ namespace IW4MAdmin Broadcast("IW4M Admin is now ^2ONLINE"); #endif - while (errors <=5) + while (isRunning) { #if DEBUG == false try @@ -536,7 +558,6 @@ namespace IW4MAdmin catch (Exception E) { Log.Write("Something unexpected occured. Hopefully we can ignore it - " + E.Message + " @" + Utilities.GetLineNumber(E), Log.Level.All); - errors++; continue; } #endif @@ -559,27 +580,36 @@ namespace IW4MAdmin timesFailed++; Log.Write("Server appears to be offline - " + timesFailed, Log.Level.Debug); - if (timesFailed > 4) + if (timesFailed >= 4) { Log.Write("Max offline attempts reached. Reinitializing RCON connection.", Log.Level.Debug); RCON.Reset(); timesFailed = 0; } - else + Utilities.Wait(10); // cut the time in half to make sure it isn't changing a map + IPS = Utilities.IPFromStatus(RCON.addRCON("status")); + } + + Log.Write("Server responded to status query!", Log.Level.Debug); + timesFailed = 0; + + foreach(Player P in players) //Ensures uniformity between server and admin players + { + if (P == null) + continue; + + String IP = String.Empty; + IPS.TryGetValue(P.getID(), out IP); + if (IP == String.Empty) { - Log.Write("Server responded to status query!", Log.Level.All); - timesFailed = 0; + Log.Write("Invalid player detected, quit event must have been skipped!", Log.Level.All); + removePlayer(P.getClientNum()); } - - Thread.Sleep(FLOOD_TIMEOUT); - - IPS = Utilities.IPFromStatus(RCON.addRCON("status")); - Utilities.Wait(1); } lastPoll = DateTime.Now; - Utilities.Wait(20); + Utilities.Wait(20); // don't want to overload the server } } @@ -808,19 +838,30 @@ namespace IW4MAdmin } Log.Write(E.Origin.getName() + " killed " + E.Target.getName() + " with a " + E.Data, Log.Level.Debug); - E.Origin.stats.Kills++; - E.Origin.stats.updateKDR(); - E.Origin.stats.lastMew = TrueSkill.calculateWinnerMu(E.Origin.stats, E.Target.stats); + if (E.Origin != E.Target) + { + E.Origin.stats.Kills++; + E.Origin.stats.updateKDR(); - E.Origin.stats.lastSigma = TrueSkill.calculateWinnerSigma(E.Origin.stats, E.Target.stats); - E.Origin.stats.updateSkill(); + E.Origin.stats.lastMew = TrueSkill.calculateWinnerMu(E.Origin.stats, E.Target.stats); + E.Origin.stats.lastSigma = TrueSkill.calculateWinnerSigma(E.Origin.stats, E.Target.stats); + E.Origin.stats.updateSkill(); - E.Target.stats.Deaths++; - E.Target.stats.updateKDR(); + E.Target.stats.Deaths++; + E.Target.stats.updateKDR(); - E.Target.stats.lastMew = TrueSkill.calculateLoserMu(E.Target.stats, E.Origin.stats); - E.Target.stats.lastSigma = TrueSkill.calculateLoserSigma(E.Target.stats, E.Origin.stats); + E.Target.stats.lastMew = TrueSkill.calculateLoserMu(E.Target.stats, E.Origin.stats); + E.Target.stats.lastSigma = TrueSkill.calculateLoserSigma(E.Target.stats, E.Origin.stats); + + totalKills++; + } + + else //Suicide + { + E.Origin.stats.Deaths++; + E.Origin.stats.updateKDR(); + } } if (E.Type == Event.GType.Say) @@ -955,7 +996,7 @@ namespace IW4MAdmin { if (B.getID() == Target.getID()) { - clientDB.removeBan(GUID); + clientDB.removeBan(Target.getID()); Bans.Remove(B); Player P = clientDB.getPlayer(Target.getID(), 0); P.setLevel(Player.Permission.User); @@ -1000,6 +1041,22 @@ namespace IW4MAdmin return Utilities.removeNastyChars(Quote); } + public void ToAdmins(String message) + { + List admins = players; + foreach (Player P in admins) + { + if (P == null) + continue; + + if (P.getLevel() > Player.Permission.User) + { + RCON.addRCON("admin_lastevent alert;" + P.getID() + ";0;mp_killstreak_nuclearstrike"); + P.Tell(message); + } + } + } + //END //THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/ @@ -1013,6 +1070,8 @@ namespace IW4MAdmin Macros = new Dictionary(); Macros.Add("WISDOM", Wisdom()); Macros.Add("TOTALPLAYERS", clientDB.totalPlayers()); + Macros.Add("TOTALKILLS", totalKills); + } private void initMaps() @@ -1121,12 +1180,12 @@ namespace IW4MAdmin commands.Add(new _Stats("stats", "view your stats or another player's. syntax: !stats", "xlrstats", Player.Permission.User, 0, true)); commands.Add(new TopStats("topstats", "view the top 4 players on this server. syntax: !topstats", "xlrtopstats", Player.Permission.User, 0, false)); commands.Add(new Reload("reload", "reload configurations. syntax: !reload", "reload", Player.Permission.Owner, 0, false)); - /* - commands.Add(new commands { command = "stats", desc = "view your server stats.", requiredPer = 0 }); - commands.Add(new commands { command = "speed", desc = "change player speed. syntax: !speed ", requiredPer = 3 }); - commands.Add(new commands { command = "gravity", desc = "change game gravity. syntax: !gravity ", requiredPer = 3 }); - - commands.Add(new commands { command = "version", desc = "view current app version.", requiredPer = 0 });*/ + commands.Add(new Balance("balance", "balance teams. syntax !balance", "bal", Player.Permission.Moderator, 0, false)); + commands.Add(new GoTo("goto", "teleport to selected player. syntax !goto", "go", Player.Permission.SeniorAdmin, 1, 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 _Report("report", "report a player for suspicious behaivor. syntax !report ", "rep", Player.Permission.User, 2, true)); + commands.Add(new Reports("reports", "get most recent reports. syntax !reports", "reports", Player.Permission.Moderator, 0, false)); + commands.Add(new _Tell("tell", "send onscreen message to player. synrax !tell ", "t", Player.Permission.Moderator, 2, true)); } //Objects @@ -1143,6 +1202,8 @@ namespace IW4MAdmin public Heartbeat HB; public String Website; public String Gametype; + public int totalKills = 0; + public List Reports; //Info private String IP; @@ -1157,7 +1218,6 @@ namespace IW4MAdmin private int messageTime; private TimeSpan lastMessage; private int nextMessage; - private int errors = 0; private String IW_Ver; private int maxClients; private Dictionary Macros; diff --git a/Admin/Utilities.cs b/Admin/Utilities.cs index 3eeef355..c94f7643 100644 --- a/Admin/Utilities.cs +++ b/Admin/Utilities.cs @@ -57,7 +57,10 @@ namespace IW4MAdmin public static String removeNastyChars(String str) { - return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace(""", "''").Replace("&", "&").Replace("\"", "''"); + if (str != null) + return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace(""", "''").Replace("&", "&").Replace("\"", "''"); + else + return String.Empty; } public static int GetLineNumber(Exception ex) @@ -86,6 +89,8 @@ namespace IW4MAdmin { case Player.Permission.Banned: return "^1" + Player.Permission.Banned; + case Player.Permission.Flagged: + return "^0" + Player.Permission.Flagged; case Player.Permission.Owner: return "^5" + Player.Permission.Owner; case Player.Permission.User: diff --git a/Admin/version.txt b/Admin/version.txt index 3be8ba2c..a6cd2390 100644 --- a/Admin/version.txt +++ b/Admin/version.txt @@ -1,4 +1,4 @@ -VERSION: 0.6 +VERSION: 0.7 CHANGELOG: --stability fixes --welcome has post-fixed connection indicator +-rcon tweaks +-so much stuff cant remember