diff --git a/Admin/Bans.cs b/Admin/Bans.cs index 3c2e4d98a..c2dc9c62f 100644 --- a/Admin/Bans.cs +++ b/Admin/Bans.cs @@ -6,12 +6,13 @@ namespace IW4MAdmin { class Ban { - public Ban(String Reas, String TargID, String From) + public Ban(String Reas, String TargID, String From, DateTime time, String ip) { Reason = Reas; npID = TargID; bannedByID = From; - When = DateTime.Now; + When = time; + IP = ip; } public String getReason() @@ -28,11 +29,22 @@ namespace IW4MAdmin { return bannedByID; } + + public String getIP() + { + return IP; + } + + public String getWhen() + { + return When.ToString("yyyy-MM-dd HH:mm:ss"); ; + } private String Reason; private String npID; private String bannedByID; private DateTime When; + private String IP; } diff --git a/Admin/Command.cs b/Admin/Command.cs index 661a36594..2c831c5bf 100644 --- a/Admin/Command.cs +++ b/Admin/Command.cs @@ -70,7 +70,7 @@ namespace IW4MAdmin E.Origin.setLevel(Player.Permission.Owner); E.Origin.Tell("Congratulations, you have claimed ownership of this server!"); E.Owner.owner = E.Origin; - E.Owner.DB.updatePlayer(E.Origin); + E.Owner.clientDB.updatePlayer(E.Origin); } else E.Origin.Tell("This server already has an owner!"); @@ -168,15 +168,10 @@ namespace IW4MAdmin E.Target.LastOffense = Utilities.removeWords(E.Data, 1); E.Target.lastEvent = E; // needs to be fixed String Message; -#if DEBUG - Message = "^1Player Banned: ^5" + E.Target.LastOffense + "^7 (appeal at nbsclan.org)"; -#else if (E.Owner.Website == null) Message = "^1Player Banned: ^5" + E.Target.LastOffense; else Message = "^1Player Banned: ^5" + E.Target.LastOffense + "^7 (appeal at " + E.Owner.Website + ")"; - -#endif if (E.Origin.getLevel() > E.Target.getLevel()) { E.Target.Ban(Message, E.Origin); @@ -324,7 +319,7 @@ namespace IW4MAdmin E.Target.Tell("Congratulations! You have been promoted to ^3" + newPerm); E.Origin.Tell(E.Target.getName() + " was successfully promoted!"); //NEEED TO MOVE - E.Owner.DB.updatePlayer(E.Target); + E.Owner.clientDB.updatePlayer(E.Target); } else @@ -379,8 +374,7 @@ namespace IW4MAdmin public override void Execute(Event E) { - String Quote = new Connection("http://www.iheartquotes.com/api/v1/random?max_lines=1&max_characters=200").Read(); - E.Owner.Broadcast(Utilities.removeNastyChars(Quote)); + E.Owner.Broadcast(E.Owner.Wisdom()); } } @@ -417,16 +411,32 @@ namespace IW4MAdmin public override void Execute(Event E) { - var db_players = E.Owner.DB.findPlayers(E.Data.Trim()); + 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 = String.Format("[^3{0}^7] [^3@{1}^7] - {2} [{3}^7]", P.getName(), P.getDBID(), P.getID(), Utilities.levelToColor(P.getLevel())); + { + String mesg; + var db_aliases = 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); } @@ -458,7 +468,7 @@ namespace IW4MAdmin public override void Execute(Event E) { E.Target.Tell("^1" + E.Origin.getName() + " ^3[PM]^7 - " + E.Data); - E.Origin.Tell("Sucessfully sent message"); + E.Origin.Tell(String.Format("To ^3{0} ^7-> {1}", E.Target.getName(), E.Data)); } } @@ -473,7 +483,7 @@ namespace IW4MAdmin else { if (E.Target.stats == null) - E.Target.stats = E.Owner.stats.getStats(E.Target.getDBID()); + E.Target.stats = E.Owner.statDB.getStats(E.Target.getDBID()); E.Origin.Tell(String.Format("[^3{4}^7] ^5{0} ^7KILLS | ^5{1} ^7DEATHS | ^5{2} ^7KDR | ^5{3} ^7SKILL", E.Target.stats.Kills, E.Target.stats.Deaths, E.Target.stats.KDR, E.Target.stats.Skill, E.Target.getName())); } } @@ -485,12 +495,12 @@ namespace IW4MAdmin public override void Execute(Event E) { - List Top = E.Owner.stats.topStats(); + List Top = E.Owner.statDB.topStats(); List TopP = new List(); foreach (Stats S in Top) { - Player P = E.Owner.DB.findPlayers(S.Kills); // BAD + Player P = E.Owner.clientDB.getPlayer(S.Kills); // BAD if (P != null && P.getLevel() != Player.Permission.Banned) { P.stats = S; @@ -512,5 +522,18 @@ namespace IW4MAdmin } } + class Reload : Command + { + public Reload(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.Reload()) + E.Origin.Tell("Sucessfully reloaded configs!"); + else + E.Origin.Tell("Unable to reload configs :("); + } + } + } diff --git a/Admin/Database.cs b/Admin/Database.cs index 0da1d3707..3dfb6c05a 100644 --- a/Admin/Database.cs +++ b/Admin/Database.cs @@ -8,226 +8,20 @@ using System.Collections; namespace IW4MAdmin { - class Database + abstract class Database { - public enum Type - { - Clients, - Stats - } - - public Database(String FN, Type T) + public Database(String FN) { FileName = FN; DBCon = String.Format("Data Source={0}", FN); Con = new SQLiteConnection(DBCon); - DBType = T; - Init(T); - } - - private void Init(Type T) - { - if(!File.Exists(FileName)) - { - switch (T) - { - case Type.Clients: - String query = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL);"; - ExecuteNonQuery(query); - query = "CREATE TABLE [BANS] ( [Reason] TEXT NULL, [npID] TEXT NULL, [bannedByID] Text NULL);"; - ExecuteNonQuery(query); - break; - case Type.Stats: - String query_stats = "CREATE TABLE [STATS] ( [Number] INTEGER, [KILLS] INTEGER DEFAULT 0, [DEATHS] INTEGER DEFAULT 0, [KDR] REAL DEFAULT 0, [SKILL] REAL DEFAULT 0 );"; - ExecuteNonQuery(query_stats); - break; - } - - } - } - - public Player getPlayer(String ID, int cNum) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE npID = '{0}' LIMIT 1", ID); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), cNum, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), ResponseRow["LastOffense"].ToString(), (int)ResponseRow["Connections"]); - } - - else - return null; - } - - public List findPlayers(String name) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Name LIKE '%{0}%' LIMIT 10", name); - DataTable Result = GetDataTable(Query); - - List Players = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow p in Result.Rows) - { - Players.Add(new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), ((int)p["Connections"]))); - } - return Players; - } - - else - return null; - } - - public Player findPlayers(int dbIndex) - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Number = '{0}' LIMIT 1", dbIndex); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow p in Result.Rows) - return new Player(p["Name"].ToString(), p["npID"].ToString(), -1, (Player.Permission)(p["Level"]), Convert.ToInt32(p["Number"]), p["LastOffense"].ToString(), ((int)p["Connections"])); - } - - return null; - } - - public Player getOwner() - { - String Query = String.Format("SELECT * FROM CLIENTS WHERE Level = '{0}'", 4); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), null, 0); - } - - else - return null; - } - - public List getBans() - { - List Bans = new List(); - DataTable Result = GetDataTable("SELECT * FROM BANS"); - - foreach (DataRow Row in Result.Rows) - Bans.Add(new Ban(Row["Reason"].ToString(), Row["npID"].ToString(), Row["bannedByID"].ToString())); - - return Bans; - } - - public Stats getStats(int DBID) - { - String Query = String.Format("SELECT * FROM STATS WHERE Number = '{0}'", DBID); - DataTable Result = GetDataTable(Query); - - if (Result != null && Result.Rows.Count > 0) - { - DataRow ResponseRow = Result.Rows[0]; - return new Stats(Convert.ToInt32(ResponseRow["KILLS"]), Convert.ToInt32(ResponseRow["DEATHS"]), Convert.ToDouble(ResponseRow["KDR"]), Convert.ToDouble(ResponseRow["SKILL"])); - } - - else - return null; - } - - public void removeBan(String GUID) - { - String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}'", GUID); - ExecuteNonQuery(Query); - } - - public void addPlayer(Player P) - { - Dictionary newPlayer = new Dictionary(); - - if (DBType == Type.Clients) - { - newPlayer.Add("Name", Utilities.removeNastyChars(P.getName())); - newPlayer.Add("npID", P.getID()); - newPlayer.Add("Level", (int)P.getLevel()); - newPlayer.Add("LastOffense", ""); - newPlayer.Add("Connections", 1); - - Insert("CLIENTS", newPlayer); - } - - if (DBType == Type.Stats) - { - newPlayer.Add("Number", P.getDBID()); - newPlayer.Add("KILLS", 0); - newPlayer.Add("DEATHS", 0); - newPlayer.Add("KDR", 0); - newPlayer.Add("SKILL", 0); - Insert("STATS", newPlayer); - } - } - - public List topStats() - { - String Query = String.Format("SELECT * FROM STATS WHERE SKILL > '{0}' ORDER BY SKILL DESC LIMIT 4", 20); - DataTable Result = GetDataTable(Query); - - List Top = new List(); - - if (Result != null && Result.Rows.Count > 0) - { - foreach (DataRow D in Result.Rows) - { - Stats S = new Stats(Convert.ToInt32(D["Number"]), Convert.ToInt32(D["DEATHS"]), Convert.ToDouble(D["KDR"]), Convert.ToDouble(D["SKILL"])); - if (S.Skill > 20) - Top.Add(S); - } - } - - return Top; - } - - public void updatePlayer(Player P) - { - Dictionary updatedPlayer = new Dictionary(); - - if (DBType == Type.Clients) - { - updatedPlayer.Add("Name", P.getName()); - updatedPlayer.Add("npID", P.getID()); - updatedPlayer.Add("Level", (int)P.getLevel()); - updatedPlayer.Add("LastOffense", P.getLastO()); - updatedPlayer.Add("Connections", P.getConnections()); - - Update("CLIENTS", updatedPlayer, String.Format("npID = '{0}'", P.getID())); - } - - if (DBType == Type.Stats) - { - updatedPlayer.Add("KILLS", P.stats.Kills); - updatedPlayer.Add("DEATHS", P.stats.Deaths); - updatedPlayer.Add("KDR", Math.Round(P.stats.KDR, 2)); - updatedPlayer.Add("SKILL", P.stats.Skill); - - Update("STATS", updatedPlayer, String.Format("Number = '{0}'", P.getDBID())); - } - } - - public void addBan(Ban B) - { - Dictionary newBan = new Dictionary(); - - newBan.Add("Reason", B.getReason()); - newBan.Add("npID", B.getID()); - newBan.Add("bannedByID", B.getBanner()); - - Insert("BANS", newBan); + Init(); } + abstract public void Init(); + //HELPERS - - public bool Insert(String tableName, Dictionary data) + protected bool Insert(String tableName, Dictionary data) { String columns = ""; String values = ""; @@ -251,7 +45,7 @@ namespace IW4MAdmin return returnCode; } - public bool Update(String tableName, Dictionary data, String where) + protected bool Update(String tableName, Dictionary data, String where) { String vals = ""; Boolean returnCode = true; @@ -275,13 +69,13 @@ namespace IW4MAdmin return returnCode; } - public DataRow getDataRow(String Q) + protected DataRow getDataRow(String Q) { DataRow Result = GetDataTable(Q).Rows[0]; return Result; } - private int ExecuteNonQuery(String Request) + protected int ExecuteNonQuery(String Request) { Con.Open(); SQLiteCommand CMD = new SQLiteCommand(Con); @@ -291,7 +85,7 @@ namespace IW4MAdmin return rowsUpdated; } - public DataTable GetDataTable(String sql) + protected DataTable GetDataTable(String sql) { DataTable dt = new DataTable(); try @@ -313,9 +107,328 @@ namespace IW4MAdmin } //END - private String FileName; - private String DBCon; - private SQLiteConnection Con; - private Type DBType; + protected String FileName; + protected String DBCon; + protected SQLiteConnection Con; + } + + class ClientsDB : Database + { + public ClientsDB(String FN) : base(FN) { } + + public override void Init() + { + if(!File.Exists(FileName)) + { + String Create = "CREATE TABLE [CLIENTS] ( [Name] TEXT NULL, [npID] TEXT NULL, [Number] INTEGER PRIMARY KEY AUTOINCREMENT, [Level] INT DEFAULT 0 NULL, [LastOffense] TEXT NULL, [Connections] INT DEFAULT 1 NULL, [IP] TEXT NULL);"; + ExecuteNonQuery(Create); + Create = "CREATE TABLE [BANS] ( [Reason] TEXT NULL, [npID] TEXT NULL, [bannedByID] TEXT NULL, [IP] TEXT NULL, [TIME] TEXT NULL);"; + ExecuteNonQuery(Create); + } + } + + //Returns a single player object with matching GUID, false if no matches + public Player getPlayer(String ID, int cNum) + { + String Query = String.Format("SELECT * FROM CLIENTS WHERE npID = '{0}' LIMIT 1", ID); + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + DataRow ResponseRow = Result.Rows[0]; + + + 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()); + } + + else + return null; + } + + //Overloaded method for getPlayer, returns Client with matching DBIndex, null if none found + public Player getPlayer(int dbIndex) + { + String Query = String.Format("SELECT * FROM CLIENTS WHERE Number = '{0}' LIMIT 1", dbIndex); + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + DataRow p = Result.Rows[0]; + + 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()); + } + + else + return null; + } + + //Returns a list of players matching name parameter, null if no players found matching + public List findPlayers(String name) + { + String Query = String.Format("SELECT * FROM CLIENTS WHERE Name LIKE '%{0}%' LIMIT 8", name); + DataTable Result = GetDataTable(Query); + + List Players = new List(); + + if (Result != null && Result.Rows.Count > 0) + { + foreach (DataRow p in Result.Rows) + { + Players.Add(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())); + } + return Players; + } + + else + return null; + } + + //Returns any player with level 4 permissions, null if no owner found + public Player getOwner() + { + String Query = String.Format("SELECT * FROM CLIENTS WHERE Level = '{0}'", 4); + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + DataRow ResponseRow = Result.Rows[0]; + if (ResponseRow["IP"].ToString().Length < 6) + ResponseRow["IP"] = "0"; + return new Player(ResponseRow["Name"].ToString(), ResponseRow["npID"].ToString(), -1, (Player.Permission)(ResponseRow["Level"]), Convert.ToInt32(ResponseRow["Number"]), null, 0, ResponseRow["IP"].ToString()); + } + + else + return null; + } + + //Returns list of bans in database + public List getBans() + { + List Bans = new List(); + DataTable Result = GetDataTable("SELECT * FROM BANS"); + + foreach (DataRow Row in Result.Rows) + { + 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 + + Bans.Add(new Ban(Row["Reason"].ToString(), Row["npID"].ToString(), Row["bannedByID"].ToString(), DateTime.Parse(Row["TIME"].ToString()), Row["IP"].ToString())); + } + + return Bans; + } + + //Returns total number of player entries in database + public int totalPlayers() + { + DataTable Result = GetDataTable("SELECT * from CLIENTS ORDER BY Number DESC LIMIT 1"); + if (Result.Rows.Count > 0) + return Convert.ToInt32(Result.Rows[0]["Number"]); + else + return 0; + } + + //Add specified player to database + public void addPlayer(Player P) + { + Dictionary newPlayer = new Dictionary(); + + newPlayer.Add("Name", Utilities.removeNastyChars(P.getName())); + newPlayer.Add("npID", P.getID()); + newPlayer.Add("Level", (int)P.getLevel()); + newPlayer.Add("LastOffense", ""); + newPlayer.Add("Connections", 1); + newPlayer.Add("IP", P.getIP()); + + Insert("CLIENTS", newPlayer); + } + + ///Update information of specified player + public void updatePlayer(Player P) + { + Dictionary updatedPlayer = new Dictionary(); + + updatedPlayer.Add("Name", P.getName()); + updatedPlayer.Add("npID", P.getID()); + updatedPlayer.Add("Level", (int)P.getLevel()); + updatedPlayer.Add("LastOffense", P.getLastO()); + updatedPlayer.Add("Connections", P.getConnections()); + updatedPlayer.Add("IP", P.getIP()); + + Update("CLIENTS", updatedPlayer, String.Format("npID = '{0}'", P.getID())); + } + + + //Add specified ban to database + public void addBan(Ban B) + { + Dictionary newBan = new Dictionary(); + + newBan.Add("Reason", B.getReason()); + newBan.Add("npID", B.getID()); + newBan.Add("bannedByID", B.getBanner()); + newBan.Add("IP", B.getIP()); + newBan.Add("TIME", Utilities.DateTimeSQLite(DateTime.Now)); + + Insert("BANS", newBan); + } + + + //Deletes ban with matching GUID + public void removeBan(String GUID) + { + String Query = String.Format("DELETE FROM BANS WHERE npID = '{0}'", GUID); + ExecuteNonQuery(Query); + } + + + } + + class StatsDB : Database + { + public StatsDB(String FN) : base(FN) { } + + public override void Init() + { + if (!File.Exists(FileName)) + { + String Create = "CREATE TABLE [STATS] ( [Number] INTEGER, [KILLS] INTEGER DEFAULT 0, [DEATHS] INTEGER DEFAULT 0, [KDR] REAL DEFAULT 0, [SKILL] REAL DEFAULT 0 );"; + ExecuteNonQuery(Create); + } + } + + // Return stats for player specified by Database ID, null if no matches + public Stats getStats(int DBID) + { + String Query = String.Format("SELECT * FROM STATS WHERE Number = '{0}'", DBID); + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + DataRow ResponseRow = Result.Rows[0]; + return new Stats(Convert.ToInt32(ResponseRow["KILLS"]), Convert.ToInt32(ResponseRow["DEATHS"]), Convert.ToDouble(ResponseRow["KDR"]), Convert.ToDouble(ResponseRow["SKILL"])); + } + + else + return null; + } + + public void addPlayer(Player P) + { + Dictionary newPlayer = new Dictionary(); + + newPlayer.Add("Number", P.getDBID()); + newPlayer.Add("KILLS", 0); + newPlayer.Add("DEATHS", 0); + newPlayer.Add("KDR", 0); + newPlayer.Add("SKILL", 1); + + Insert("STATS", newPlayer); + } + + //Update stat information of specified player + public void updatePlayer(Player P) + { + Dictionary updatedPlayer = new Dictionary(); + + updatedPlayer.Add("KILLS", P.stats.Kills); + updatedPlayer.Add("DEATHS", P.stats.Deaths); + updatedPlayer.Add("KDR", Math.Round(P.stats.KDR, 2)); + updatedPlayer.Add("SKILL", P.stats.Skill); + + Update("STATS", updatedPlayer, String.Format("Number = '{0}'", P.getDBID())); + } + + //Returns top 8 players (we filter through them later) + public List topStats() + { + String Query = String.Format("SELECT * FROM STATS WHERE SKILL > '{0}' ORDER BY SKILL DESC LIMIT 8", 20); + DataTable Result = GetDataTable(Query); + + List Top = new List(); + + if (Result != null && Result.Rows.Count > 0) + { + foreach (DataRow D in Result.Rows) + { + Stats S = new Stats(Convert.ToInt32(D["Number"]), Convert.ToInt32(D["DEATHS"]), Convert.ToDouble(D["KDR"]), Convert.ToDouble(D["SKILL"])); + if (S.Skill > 20) + Top.Add(S); + } + } + + return Top; + } + + public void clearSkill() + { + String Query = "SELECT * FROM STATS"; + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + foreach (DataRow D in Result.Rows) + Update("STATS", new Dictionary () { {"SKILL", 1} }, String.Format("Number = '{0}'", D["Number"])); + } + } + } + + class AliasesDB : Database + { + public AliasesDB(String FN) : base(FN) { } + + public override void Init() + { + if (!File.Exists(FileName)) + { + String Create = "CREATE TABLE [ALIASES] ( [Number] INTEGER, [NAMES] TEXT NULL, [IPS] TEXTNULL );"; + ExecuteNonQuery(Create); + } + } + + public Aliases getPlayer(int dbIndex) + { + String Query = String.Format("SELECT * FROM ALIASES WHERE Number = '{0}' LIMIT 1", dbIndex); + DataTable Result = GetDataTable(Query); + + if (Result != null && Result.Rows.Count > 0) + { + DataRow p = Result.Rows[0]; + return new Aliases(Convert.ToInt32(p["Number"]), p["NAMES"].ToString(), p["IPS"].ToString()); + } + + else + return null; + } + + public void addPlayer(Aliases Alias) + { + Dictionary newPlayer = new Dictionary(); + + newPlayer.Add("Number", Alias.getNumber()); + newPlayer.Add("NAMES", Alias.getNamesDB()); + newPlayer.Add("IPS", Alias.getIPSDB()); + + Insert("ALIASES", newPlayer); + } + + public void updatePlayer(Aliases Alias) + { + Dictionary updatedPlayer = new Dictionary(); + + updatedPlayer.Add("Number", Alias.getNumber()); + updatedPlayer.Add("NAMES", Alias.getNamesDB()); + updatedPlayer.Add("IPS", Alias.getIPSDB()); + + Update("ALIASES", updatedPlayer, String.Format("Number = '{0}'", Alias.getNumber())); + } } } diff --git a/Admin/Heartbeat.cs b/Admin/Heartbeat.cs index b89fc8703..8fd6e601c 100644 --- a/Admin/Heartbeat.cs +++ b/Admin/Heartbeat.cs @@ -14,7 +14,7 @@ namespace IW4MAdmin public void Send() { - String URI = String.Format("http://raidmax.org/IW4M/Admin/heartbeat.php?address={0}&name={1}&map={2}&players={3}", Instance.getPort().ToString(), Instance.getName(), Instance.getMap(), Instance.getClientNum().ToString() + '/' + Instance.getMaxClients().ToString()); + String URI = String.Format("http://raidmax.org/IW4M/Admin/heartbeat.php?address={0}&name={1}&map={2}&players={3}&version={4}", Instance.getPort().ToString(), Instance.getName(), Instance.getMap(), Instance.getClientNum().ToString() + '/' + Instance.getMaxClients().ToString(), IW4MAdmin.Program.Version.ToString()); Handle.Request(URI); } diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj index c56609be0..d75e9be0a 100644 --- a/Admin/IW4M ADMIN.csproj +++ b/Admin/IW4M ADMIN.csproj @@ -28,7 +28,7 @@ RaidMax LLC true publish.htm - 5 + 6 0.4.0.%2a false true diff --git a/Admin/Main.cs b/Admin/Main.cs index cd014c09e..74a5e4fc6 100644 --- a/Admin/Main.cs +++ b/Admin/Main.cs @@ -10,7 +10,7 @@ namespace IW4MAdmin static String IP; static int Port; static String RCON; - static public double Version = 0.4; + static public double Version = 0.5; static public double latestVersion; static void Main(string[] args) diff --git a/Admin/Player.cs b/Admin/Player.cs index 4f310ef43..3b27d8df7 100644 --- a/Admin/Player.cs +++ b/Admin/Player.cs @@ -6,7 +6,7 @@ namespace IW4MAdmin { class Stats { - public Stats(int K, int D, double kdr, double skill) + public Stats(int K, int D, double kdr, double skill) { Kills = K; Deaths = D; @@ -21,8 +21,7 @@ namespace IW4MAdmin public void updateSkill(double enemySkill) { - Skill = (Math.Round((double)Kills * (((double)Kills / (double)Deaths) / 10), 2)); - Skill = Math.Round(Math.Log(Skill) * (enemySkill / 2) + (Math.Log(Deaths + 1) * 0.3) * 12, 2); + Skill = Math.Round(Math.Log(KDR + 1) * ((enemySkill / 2) + 1) + (Math.Log(Deaths) * 0.3) * 12, 2); } public int Kills; @@ -31,6 +30,55 @@ namespace IW4MAdmin public double Skill; } + class Aliases + { + public Aliases(int Num, String N, String I) + { + Number = Num; + Names = N; + IPS = I; + } + + public List getNames() + { + return new List(Names.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + } + + public List getIPS() + { + return new List(IPS.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)); + } + + public String getIPSDB() + { + return IPS; + } + + public String getNamesDB() + { + return Names; + } + + public int getNumber() + { + return Number; + } + + public void addName(String Name) + { + Names += Names + ';'; + } + + public void addIP(String IP) + { + IPS += IP + ';'; + } + + private String Names; + private String IPS; + private int Number; + } + class Player { public enum Permission @@ -55,7 +103,7 @@ namespace IW4MAdmin Warnings = 0; } - public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con) + public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2) { Name = n; npID = id; @@ -64,6 +112,7 @@ namespace IW4MAdmin dbID = cind; LastOffense = lo; Connections = con + 1; + IP = IP2; Warnings = 0; } @@ -102,11 +151,21 @@ namespace IW4MAdmin return LastOffense; } + public String getIP() + { + return IP; + } + public void updateName(String n) { Name = n; } + public void updateIP(String I) + { + IP = I; + } + // BECAUSE IT NEEDS TO BE CHANGED! public void setLevel(Player.Permission Perm) { @@ -158,10 +217,12 @@ namespace IW4MAdmin private Player.Permission Level; private int dbID; private int Connections; + private String IP; public Event lastEvent; public String LastOffense; public int Warnings; public Stats stats; + public Aliases Alias; } } diff --git a/Admin/RCON.cs b/Admin/RCON.cs index a0ae6edc1..701a2e98b 100644 --- a/Admin/RCON.cs +++ b/Admin/RCON.cs @@ -22,52 +22,17 @@ namespace IW4MAdmin sv_connection.Client.SendTimeout = 1000; sv_connection.Client.ReceiveTimeout = 1000; Instance = I; - toSend = new Queue(); + toSend = new Queue(); } - //When we don't care about a response - public bool sendRCON(String message) - { - try - { - String STR_REQUEST = String.Format("ÿÿÿÿrcon {0} {1}", Instance.getPassword(), message); - - Byte[] Request_ = Encoding.Unicode.GetBytes(STR_REQUEST); - Byte[] Request = new Byte[Request_.Length / 2]; - - int count = 0; //This is kinda hacky but Unicode -> ASCII doesn't seem to be working correctly for this. - foreach (Byte b in Request_) - { - if (b != 0) - Request[count / 2] = b; - count++; - } - - - System.Net.IPAddress IP = System.Net.IPAddress.Parse(Instance.getIP()); - IPEndPoint endPoint = new IPEndPoint(IP, Instance.getPort()); - - sv_connection.Connect(endPoint); - sv_connection.Send(Request, Request.Length); - } - - catch (SocketException) - { - Instance.Log.Write("Unable to reach server for sending RCON", Log.Level.Debug); - sv_connection.Close(); - return false; - } - - return true; - } //We want to read the reponse public String[] responseSendRCON(String message) { try { - String STR_REQUEST; + String STR_REQUEST = String.Empty; if (message != "getstatus") - STR_REQUEST = String.Format("ÿÿÿÿrcon {0} {1}", Instance.getPassword().Replace("\r", String.Empty), message); + STR_REQUEST = String.Format("ÿÿÿÿrcon {0} {1}", Instance.getPassword(), message); else STR_REQUEST = String.Format("ÿÿÿÿ getstatus"); @@ -88,33 +53,50 @@ namespace IW4MAdmin sv_connection.Connect(endPoint); sv_connection.Send(Request, Request.Length); - - Byte[] receive = sv_connection.Receive(ref endPoint); - int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier); + String incoming = String.Empty; + byte[] bufferRecv = new byte[65536]; + do + { + // loop on receiving the bytes + bufferRecv = sv_connection.Receive(ref endPoint); - String[] response = System.Text.Encoding.UTF8.GetString(receive).Split((char)num); + // only decode the bytes received + incoming += (Encoding.ASCII.GetString(bufferRecv, 0, bufferRecv.Length)); + } while (sv_connection.Available > 0); + + int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier); + + String[] response = incoming.Split(new char[] {(char)num} , StringSplitOptions.RemoveEmptyEntries); if(response[1] == "Invalid password.") { Instance.Log.Write("Invalid RCON password specified", Log.Level.Debug); return null; } - return response; } catch (SocketException) { Instance.Log.Write("Unable to reach server for sending RCON", Log.Level.Debug); + return null; + } + + catch (System.InvalidOperationException) + { + Instance.Log.Write("RCON Connection terminated by server. Uh-OH", Log.Level.Debug); sv_connection.Close(); + sv_connection = new UdpClient(); return null; } } - public void addRCON(String Message, int delay) + public String[] addRCON(String Message) { - toSend.Enqueue(Message); + RCON_Request newReq = new RCON_Request(Message); + toSend.Enqueue(newReq); + return newReq.waitForResponse(); } public void ManageRCONQueue() @@ -123,7 +105,8 @@ namespace IW4MAdmin { if (toSend.Count > 0) { - sendRCON(toSend.Peek()); + RCON_Request Current = toSend.Peek(); + Current.Response = responseSendRCON(Current.Request); toSend.Dequeue(); Utilities.Wait(0.567); } @@ -134,6 +117,31 @@ namespace IW4MAdmin private UdpClient sv_connection; private Server Instance; - private Queue toSend; + private Queue toSend; } + + class RCON_Request + { + public RCON_Request(String IN) + { + Request = IN; + Response = null; + } + + public String[] waitForResponse() + { + DateTime Start = DateTime.Now; + DateTime Current = DateTime.Now; + while (Response == null && (Current-Start).TotalMilliseconds < 1000) + { + Thread.Sleep(1); + Current = DateTime.Now; + } + return Response; + } + + public String Request; + public String[] Response; + } + } diff --git a/Admin/Server.cs b/Admin/Server.cs index 070066f80..399b6904f 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -1,6 +1,7 @@  using System; using System.Collections.Generic; +using System.Collections; using System.Text; using System.Threading; //SLEEP using System.IO; @@ -20,19 +21,23 @@ namespace IW4MAdmin clientnum = 0; RCON = new RCON(this); logFile = new file("admin_" + port + ".log", true); +#if DEBUG + Log = new Log(logFile, Log.Level.Debug); +#else Log = new Log(logFile, Log.Level.Production); +#endif players = new List(new Player[18]); - DB = new Database("clients.rm", Database.Type.Clients); - stats = new Database("stats_" + port + ".rm", Database.Type.Stats); - Bans = DB.getBans(); - owner = DB.getOwner(); - maps = new List(); - rules = new List(); - messages = new List(); + clientDB = new ClientsDB("clients.rm"); + statDB = new StatsDB("stats_" + port + ".rm"); + aliasDB = new AliasesDB("aliases.rm"); + Bans = clientDB.getBans(); + owner = clientDB.getOwner(); events = new Queue(); HB = new Heartbeat(this); + Macros = new Dictionary(); nextMessage = 0; initCommands(); + initMacros(); initMessages(); initMaps(); initRules(); @@ -100,41 +105,72 @@ namespace IW4MAdmin { try { - if (DB.getPlayer(P.getID(), P.getClientNum()) == null) - DB.addPlayer(P); - else + if (clientDB.getPlayer(P.getID(), P.getClientNum()) == null) { - //messy way to prevent loss of last event - Player A; - A = DB.getPlayer(P.getID(), P.getClientNum()); - if (A.getName() != P.getName()) - A.updateName(P.getName()); - A.lastEvent = P.lastEvent; - P = A; + clientDB.addPlayer(P); + Player New = clientDB.getPlayer(P.getID(), P.getClientNum()); + statDB.addPlayer(New); + aliasDB.addPlayer(new Aliases(New.getDBID(), New.getName(), New.getIP())); } - P.stats = stats.getStats(P.getDBID()); - if (P.stats == null) - { - stats.addPlayer(P); - P.stats = new Stats(0, 0, 0, 1); - } - if(players[P.getClientNum()] == null) + //messy way to prevent loss of last event + Player NewPlayer = clientDB.getPlayer(P.getID(), P.getClientNum()); + NewPlayer.stats = statDB.getStats(NewPlayer.getDBID()); + if (NewPlayer.stats == null) + { + statDB.addPlayer(NewPlayer); + NewPlayer.stats = statDB.getStats(NewPlayer.getDBID()); + } + NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.getDBID()); + NewPlayer.lastEvent = P.lastEvent; + + if (players[NewPlayer.getClientNum()] == null) + { + try + { + P.updateIP(IPS[P.getID()]); + } + + catch + { + Log.Write("Looks like the connecting player doesn't have an IP location assigned yet.", Log.Level.Debug); + P.updateIP(getPlayerIP(P.getID())); + } + + if (P.getName() != NewPlayer.getName()) + { + NewPlayer.updateName(P.getName()); + NewPlayer.Alias.addName(P.getName()); + } + + if (P.getIP() != NewPlayer.getIP()) + { + NewPlayer.updateIP(P.getIP()); + NewPlayer.Alias.addIP(P.getIP()); + } + clientnum++; + } - players[P.getClientNum()] = null; - players[P.getClientNum()] = P; + NewPlayer.lastEvent = P.lastEvent; - if (P.getLevel() == Player.Permission.Banned) + players[NewPlayer.getClientNum()] = null; + players[NewPlayer.getClientNum()] = NewPlayer; + + Ban B = isBanned(NewPlayer); + if (NewPlayer.getLevel() == Player.Permission.Banned || B != null) { Log.Write("Banned client " + P.getName() + " trying to connect...", Log.Level.Debug); - String Message = "^1Player Kicked: ^7Previously Banned for ^5" + isBanned(P).getReason(); + String Message = "^1Player Kicked: ^7Previously Banned for ^5" + B.getReason(); P.Kick(Message); } else - Log.Write("Client " + P.getName() + " connecting...", Log.Level.Debug); + Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); + + clientDB.updatePlayer(NewPlayer); + aliasDB.updatePlayer(NewPlayer.Alias); return true; } @@ -148,6 +184,8 @@ namespace IW4MAdmin //Remove player by CLIENT NUMBER public bool removePlayer(int cNum) { + Log.Write("Updating stats for " + players[cNum].getName(), Log.Level.Debug); + statDB.updatePlayer(players[cNum]); Log.Write("Client at " + cNum + " disconnecting...", Log.Level.Debug); players[cNum] = null; clientnum--; @@ -197,18 +235,38 @@ namespace IW4MAdmin public Ban isBanned(Player C) { - if (C.getLevel() == Player.Permission.Banned) - { foreach (Ban B in Bans) { + if (B.getID() == C.getID()) return B; + + if (B.getIP() == null) + continue; + + if (C.Alias.getIPS().Find(f => f.Contains(B.getIP())) != null) + return B; + + if (C.getIP() == B.getIP()) + return B; } - } return null; } + public String getPlayerIP(String GUID) + { + Dictionary dict; + int count = 0; + do + { + //because rcon can be weird + dict = Utilities.IPFromStatus(RCON.addRCON("status")); + count++; + } while(dict.Count < clientnum || count < 5); + return dict[GUID]; + } + public Command processCommand(Event E, Command C) { E.Data = Utilities.removeWords(E.Data, 1); @@ -238,7 +296,7 @@ namespace IW4MAdmin { int dbID = -1; int.TryParse(Args[0].Substring(1, Args[0].Length-1), out dbID); - Player found = E.Owner.DB.findPlayers(dbID); + Player found = E.Owner.clientDB.getPlayer(dbID); if (found != null) E.Target = found; } @@ -282,22 +340,23 @@ namespace IW4MAdmin //Starts the monitoring process public void Monitor() { - if (!intializeBasics()) - { - Log.Write("Stopping " + Port + " due to uncorrectable errors (check log)" + logPath, Log.Level.Production); - Utilities.Wait(10); - return; - } //Handles new rcon requests in a fashionable manner Thread RCONQueue = new Thread(new ThreadStart(RCON.ManageRCONQueue)); RCONQueue.Start(); + if (!intializeBasics()) + { + Log.Write("Stopping " + Port + " due to uncorrectable errors (check log)" + logPath, Log.Level.Production); + Utilities.Wait(10); + return; + } + //Handles new events in a fashionable manner Thread eventQueue = new Thread(new ThreadStart(manageEventQueue)); eventQueue.Start(); - int timeFailed = 0; + int timesFailed = 0; long l_size = -1; String[] lines = new String[8]; String[] oldLines = new String[8]; @@ -313,13 +372,24 @@ namespace IW4MAdmin lastMessage = DateTime.Now - start; if(lastMessage.TotalSeconds > messageTime && messages.Count > 0) { - Broadcast(messages[nextMessage]); + + if (RCON.responseSendRCON("sv_online") == null) + { + timesFailed++; + Log.Write("Server appears to be offline - " + timesFailed, Log.Level.Debug); + } + else + timesFailed = 0; + Thread.Sleep(300); + initMacros(); + Broadcast(Utilities.processMacro(Macros, messages[nextMessage])); if (nextMessage == (messages.Count - 1)) nextMessage = 0; else nextMessage++; start = DateTime.Now; - HB.Send(); + if (timesFailed <= 3) + HB.Send(); } if (l_size != logFile.getSize()) @@ -385,10 +455,10 @@ namespace IW4MAdmin //Vital RCON commands to establish log file and server name. May need to cleanup in the future private bool intializeBasics() { - try + try { - String[] infoResponse = RCON.responseSendRCON("getstatus"); - + String[] infoResponse = RCON.addRCON("getstatus"); + if (infoResponse == null || infoResponse.Length < 2) { Log.Write("Could not get server status!", Log.Level.All); @@ -396,32 +466,40 @@ namespace IW4MAdmin } infoResponse = infoResponse[1].Split('\\'); - mapname = infoResponse[20]; - mapname = maps.Find(m => m.Name.Equals(mapname)).Alias; - hostname = Utilities.stripColors(infoResponse[32]); - IW_Ver = infoResponse[2]; - maxClients = Convert.ToInt32(infoResponse[6]); - Gametype = infoResponse[8]; + Dictionary infoResponseDict = new Dictionary(); - //get _Website - String[] p = RCON.responseSendRCON("_Website"); - - if (p == null) + for (int i = 0; i < infoResponse.Length; i++) { - Log.Write("Could not website name!", Log.Level.All); - return false; + if (i%2 == 0 || infoResponse[i] == String.Empty) + continue; + infoResponseDict.Add(infoResponse[i], infoResponse[i+1]); } - p = p[1].Split('"'); - if (p[0].Trim() != "Unknown command") - Website = (p[3].Substring(0, p[3].Length - 2).Trim()); - p = null; - //END + mapname = infoResponseDict["mapname"]; + try + { + mapname = maps.Find(m => m.Name.Equals(mapname)).Alias; + } - Thread.Sleep(FLOOD_TIMEOUT); + catch(Exception) + { + Log.Write(mapname + " doesn't appear to be in the maps.cfg", Log.Level.Debug); + } - //GET fs_basepath - p = RCON.responseSendRCON("fs_basepath"); + hostname = Utilities.stripColors(infoResponseDict["sv_hostname"]); + IW_Ver = infoResponseDict["shortversion"]; + maxClients = Convert.ToInt32(infoResponseDict["sv_maxclients"]); + Gametype = infoResponseDict["g_gametype"]; + try + { + Website = infoResponseDict["_Website"]; + } + catch (Exception E) + { + Log.Write("Seems not to have website specified", Log.Level.Debug); + } + + String[] p =RCON.addRCON("fs_basepath"); if (p == null) { @@ -432,12 +510,10 @@ namespace IW4MAdmin p = p[1].Split('"'); Basepath = p[3].Substring(0, p[3].Length - 2).Trim(); p = null; - - Thread.Sleep(FLOOD_TIMEOUT); //END //get fs_game - p = RCON.responseSendRCON("fs_game"); + p =RCON.addRCON("fs_game"); if (p == null) { @@ -449,11 +525,10 @@ namespace IW4MAdmin Mod = p[3].Substring(0, p[3].Length - 2).Trim().Replace('/', '\\'); p = null; - Thread.Sleep(FLOOD_TIMEOUT); //END //get g_log - p = RCON.responseSendRCON("g_log"); + p = RCON.addRCON("g_log"); if (p == null) { @@ -472,11 +547,10 @@ namespace IW4MAdmin string log = p[3].Substring(0, p[3].Length - 2).Trim(); p = null; - Thread.Sleep(FLOOD_TIMEOUT); //END //get g_logsync - p = RCON.responseSendRCON("g_logsync"); + p =RCON.addRCON("g_logsync"); if (p == null) { @@ -489,15 +563,12 @@ namespace IW4MAdmin int logsync = Convert.ToInt32(p[3].Substring(0, p[3].Length - 2).Trim()); p = null; - Thread.Sleep(FLOOD_TIMEOUT); if (logsync != 1) - RCON.sendRCON("g_logsync 1"); - - Thread.Sleep(FLOOD_TIMEOUT); + RCON.addRCON("g_logsync 1"); //END //get iw4m_onelog - p = RCON.responseSendRCON("iw4m_onelog"); + p =RCON.addRCON("iw4m_onelog"); if (p[0] == String.Empty || p[1].Length < 15) { @@ -510,8 +581,6 @@ namespace IW4MAdmin p = null; //END - Thread.Sleep(FLOOD_TIMEOUT); - if (Mod == String.Empty || onelog == "1") logPath = Basepath + '\\' + "m2demo" + '\\' + log; else @@ -526,6 +595,24 @@ namespace IW4MAdmin logFile = new file(logPath); Log.Write("Log file is " + logPath, Log.Level.Debug); + //get players ip's + p =RCON.addRCON("status"); + if (p == null) + { + Log.Write("Unable to get initial player list!", Log.Level.Debug); + return false; + } + + IPS = Utilities.IPFromStatus(p); + +#if DEBUG + /* System.Net.FtpWebRequest tmp = (System.Net.FtpWebRequest)System.Net.FtpWebRequest.Create("ftp://raidmax.org/logs/games_old.log"); + tmp.Credentials = new System.Net.NetworkCredential("*", "*"); + System.IO.Stream ftpStream = tmp.GetResponse().GetResponseStream(); + String ftpLog = new StreamReader(ftpStream).ReadToEnd();*/ + logPath = "games_old.log"; +#endif + return true; } catch (Exception E) @@ -544,12 +631,11 @@ namespace IW4MAdmin return true; } - if (E.Type == Event.GType.Disconnect) + if (E.Type == Event.GType.Disconnect && E.Origin.getClientNum() > 0) { - if (getNumPlayers() > 0 && E.Origin != null) + if (getNumPlayers() > 0 && E.Origin != null && players[E.Origin.getClientNum()] != null) { - DB.updatePlayer(E.Origin); - stats.updatePlayer(E.Origin); + clientDB.updatePlayer(E.Origin); removePlayer(E.Origin.getClientNum()); } return true; @@ -565,7 +651,7 @@ namespace IW4MAdmin E.Target.stats.Deaths++; E.Target.stats.updateKDR(); - E.Target.stats.updateSkill(E.Origin.stats.Skill); + //E.Target.stats.updateSkill(E.Origin.stats.Skill); } } @@ -616,7 +702,7 @@ namespace IW4MAdmin { if (P == null || P.stats == null) continue; - stats.updatePlayer(P); + statDB.updatePlayer(P); Log.Write("Updated stats for client " + P.getDBID(), Log.Level.Debug); } return true; @@ -625,32 +711,54 @@ namespace IW4MAdmin return false; } + public bool Reload() + { + try + { + messages = null; + maps = null; + rules = null; + initMaps(); + initMessages(); + initRules(); + return true; + } + catch (Exception E) + { + Log.Write("Unable to reload configs! - " + E.Message, Log.Level.Debug); + messages = new List(); + maps = new List(); + rules = new List(); + return false; + } + } + //THESE MAY NEED TO BE MOVED public void Broadcast(String Message) { - RCON.addRCON("sayraw " + Message, 0); + RCON.addRCON("sayraw " + Message); } public void Tell(String Message, Player Target) { - RCON.addRCON("tell " + Target.getClientNum() + " " + Message + "^7", 0); + RCON.addRCON("tell " + Target.getClientNum() + " " + Message + "^7"); } public void Kick(String Message, Player Target) { - RCON.addRCON("clientkick " + Target.getClientNum() + " \"" + Message + "^7\"", 0); + RCON.addRCON("clientkick " + Target.getClientNum() + " \"" + Message + "^7\""); } public void Ban(String Message, Player Target, Player Origin) { - RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "^7\"", 0); + RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "^7\""); if (Origin != null) { Target.setLevel(Player.Permission.Banned); - Ban newBan = new Ban(Target.getLastO(), Target.getID(), Origin.getID()); + Ban newBan = new Ban(Target.getLastO(), Target.getID(), Origin.getID(), DateTime.Now, Target.getIP()); Bans.Add(newBan); - DB.addBan(newBan); - DB.updatePlayer(Target); + clientDB.addBan(newBan); + clientDB.updatePlayer(Target); } } @@ -660,11 +768,11 @@ namespace IW4MAdmin { if (B.getID() == Target.getID()) { - DB.removeBan(GUID); + clientDB.removeBan(GUID); Bans.Remove(B); - Player P = DB.getPlayer(Target.getID(), 0); + Player P = clientDB.getPlayer(Target.getID(), 0); P.setLevel(Player.Permission.User); - DB.updatePlayer(P); + clientDB.updatePlayer(P); return true; } } @@ -675,29 +783,36 @@ namespace IW4MAdmin public void fastRestart(int delay) { Utilities.Wait(delay); - RCON.addRCON("fast_restart", 0); + RCON.addRCON("fast_restart"); } public void mapRotate(int delay) { Utilities.Wait(delay); - RCON.addRCON("map_rotate", 0); + RCON.addRCON("map_rotate"); } public void tempBan(String Message, Player Target) { - RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "\"", 0); + RCON.addRCON("tempbanclient " + Target.getClientNum() + " \"" + Message + "\""); } public void mapRotate() { - RCON.addRCON("map_rotate", 0); + RCON.addRCON("map_rotate"); } public void Map(String map) { - RCON.addRCON("map " + map, 0); + RCON.addRCON("map " + map); } + + public String Wisdom() + { + String Quote = new Connection("http://www.iheartquotes.com/api/v1/random?max_lines=1&max_characters=200").Read(); + return Utilities.removeNastyChars(Quote); + } + //END //THIS IS BAD BECAUSE WE DON"T WANT EVERYONE TO HAVE ACCESS :/ @@ -706,10 +821,20 @@ namespace IW4MAdmin return rcon_pass; } + private void initMacros() + { + Macros = new Dictionary(); + Macros.Add("WISDOM", Wisdom()); + Macros.Add("TOTALPLAYERS", clientDB.totalPlayers()); + } + private void initMaps() { + maps = new List(); + file mapfile = new file("config\\maps.cfg"); String[] _maps = mapfile.readAll(); + mapfile.Close(); if (_maps.Length > 2) // readAll returns minimum one empty string { foreach (String m in _maps) @@ -728,8 +853,11 @@ namespace IW4MAdmin private void initMessages() { + messages = new List(); + file messageCFG = new file("config\\messages.cfg"); String[] lines = messageCFG.readAll(); + messageCFG.Close(); if (lines.Length < 2) //readAll returns minimum one empty string { @@ -756,8 +884,11 @@ namespace IW4MAdmin private void initRules() { + rules = new List(); + file ruleFile = new file("config\\rules.cfg"); String[] _rules = ruleFile.readAll(); + ruleFile.Close(); if (_rules.Length > 2) // readAll returns minimum one empty string { foreach (String r in _rules) @@ -793,15 +924,16 @@ namespace IW4MAdmin commands.Add(new Uptime("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.Moderator, 2, true)); commands.Add(new WarnClear("warnclear", "remove all warning for a player syntax: !warnclear .", "wc", Player.Permission.Administrator, 1, true)); - commands.Add(new Unban("unban", "unban player by guid. syntax: !unban .", "ub", Player.Permission.Administrator, 1, true)); + commands.Add(new Unban("unban", "unban player by guid. syntax: !unban .", "ub", Player.Permission.SeniorAdmin, 1, true)); commands.Add(new Admins("admins", "list currently connected admins. syntax: !admins.", "a", Player.Permission.User, 0, false)); commands.Add(new Wisdom("wisdom", "get a random wisdom quote. syntax: !wisdom", "w", Player.Permission.Administrator, 0, false)); commands.Add(new MapCMD("map", "change to specified map. syntax: !map", "m", Player.Permission.Administrator, 1, false)); - commands.Add(new Find("find", "find player in database. syntax: !find ", "f", Player.Permission.Administrator, 1, false)); + commands.Add(new Find("find", "find player in database. syntax: !find ", "f", Player.Permission.SeniorAdmin, 1, false)); commands.Add(new Rules("rules", "list server rules. syntax: !rules", "r", Player.Permission.User, 0, false)); commands.Add(new PrivateMessage("privatemessage", "send message to other player. syntax: !pm ", "pm", Player.Permission.User, 2, true)); 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 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 }); @@ -813,13 +945,14 @@ namespace IW4MAdmin //Objects public Log Log; public RCON RCON; - public Database DB; + public ClientsDB clientDB; + public AliasesDB aliasDB; + public StatsDB statDB; public List Bans; public Player owner; public List maps; public List rules; public Queue events; - public Database stats; public Heartbeat HB; public String Website; public String Gametype; @@ -840,6 +973,11 @@ namespace IW4MAdmin private int errors = 0; private String IW_Ver; private int maxClients; + private Dictionary Macros; + + + //Will probably move this later + private Dictionary IPS; //Log stuff diff --git a/Admin/Utilities.cs b/Admin/Utilities.cs index 52f9f7037..b954826b7 100644 --- a/Admin/Utilities.cs +++ b/Admin/Utilities.cs @@ -57,7 +57,7 @@ namespace IW4MAdmin public static String removeNastyChars(String str) { - return str.Replace("`", "").Replace("'", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace(""", "''"); + return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace(""", "''").Replace("&", "&").Replace("\"", "''"); } public static int GetLineNumber(Exception ex) @@ -86,17 +86,60 @@ namespace IW4MAdmin { case Player.Permission.Banned: return "^1" + Player.Permission.Banned; - break; case Player.Permission.Owner: return "^5" + Player.Permission.Owner; - break; case Player.Permission.User: return "^3" + Player.Permission.User; - break; default: return "^2" + level; - break; } } + + public static String processMacro(Dictionary Dict, String str) + { + MatchCollection Found = Regex.Matches(str, @"\{\{[A-Z]+\}\}", RegexOptions.IgnoreCase); + foreach (Match M in Found) + { + String Match = M.Value; + String Identifier = M.Value.Substring(2, M.Length - 4); + String Replacement = Dict[Identifier].ToString(); + str = str.Replace(Match, Replacement); + } + + return str; + } + + public static Dictionary IPFromStatus(String[] players) + { + Dictionary Dict = new Dictionary(); + + foreach (String S in players) + { + String S2 = S.Trim(); + if (S.Length < 50) + continue; + if (Regex.Matches(S2, @"\d+$", RegexOptions.IgnoreCase).Count > 0) + { + String[] eachPlayer = S2.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 3; i < eachPlayer.Length; i++ ) + { + if (eachPlayer[i].Split(':').Length > 1) + { + Dict.Add(eachPlayer[3], eachPlayer[i].Split(':')[0]); + break; + } + } + + } + } + return Dict; + + } + + public static String DateTimeSQLite(DateTime datetime) + { + string dateTimeFormat = "{0}-{1}-{2} {3}:{4}:{5}.{6}"; + return string.Format(dateTimeFormat, datetime.Year, datetime.Month, datetime.Day, datetime.Hour, datetime.Minute, datetime.Second, datetime.Millisecond); + } } } diff --git a/Admin/config/messages.cfg b/Admin/config/messages.cfg index c7a6c5b60..19085cbb8 100644 --- a/Admin/config/messages.cfg +++ b/Admin/config/messages.cfg @@ -1,5 +1,5 @@ 60 -This server uses ^5IW4M Admin v0.2 ^7get it at ^5raidmax.org +This server uses ^5IW4M Admin v0.5 ^7get it at ^5raidmax.org ^5IW4M Admin ^7sees ^5YOU! Cheaters are ^1unwelcome ^7 on this server Did you know 8/10 people agree with unverified statistics? \ No newline at end of file diff --git a/Admin/version.txt b/Admin/version.txt index 5cce9b370..7d837fb93 100644 --- a/Admin/version.txt +++ b/Admin/version.txt @@ -1 +1,11 @@ -0.4 \ No newline at end of file +VERSION: 0.5 +CHANGELOG: +-close config files after reading oops +-added reload command +-added macros! (Denoted by {{MACRO}} in server config right now only {{WISDOM}} and {{TOTALPLAYERS}}) +-added IP's (tracks and rebans new accounts on same banned ip)! +-aliases +-reworked database classes +-heartbeat gives running version +-player banned in find gives last ban reason +-reworked rcon yet again diff --git a/GAME/Game_TEST/Game_TEST.sln b/GAME/Game_TEST/Game_TEST.sln deleted file mode 100644 index f2a42128f..000000000 --- a/GAME/Game_TEST/Game_TEST.sln +++ /dev/null @@ -1,22 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game_TEST", "Game_TEST\Game_TEST.csproj", "{119DA221-3EA7-432C-AAFC-782D94EA1ECF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {119DA221-3EA7-432C-AAFC-782D94EA1ECF}.Debug|x86.ActiveCfg = Debug|x86 - {119DA221-3EA7-432C-AAFC-782D94EA1ECF}.Debug|x86.Build.0 = Debug|x86 - {119DA221-3EA7-432C-AAFC-782D94EA1ECF}.Release|x86.ActiveCfg = Release|x86 - {119DA221-3EA7-432C-AAFC-782D94EA1ECF}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/GAME/Game_TEST/Game_TEST/Game1.cs b/GAME/Game_TEST/Game_TEST/Game1.cs deleted file mode 100644 index 6d6fc5aca..000000000 --- a/GAME/Game_TEST/Game_TEST/Game1.cs +++ /dev/null @@ -1,91 +0,0 @@ -#region Using Statements -using System; -using System.Collections.Generic; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; -using Microsoft.Xna.Framework.Storage; -using Microsoft.Xna.Framework.GamerServices; -#endregion - -namespace Game_TEST -{ - /// - /// This is the main type for your game - /// - public class Game1 : Game - { - GraphicsDeviceManager graphics; - SpriteBatch spriteBatch; - - public Game1() - : base() - { - graphics = new GraphicsDeviceManager(this); - Content.RootDirectory = "Content"; - } - - /// - /// Allows the game to perform any initialization it needs to before starting to run. - /// This is where it can query for any required services and load any non-graphic - /// related content. Calling base.Initialize will enumerate through any components - /// and initialize them as well. - /// - protected override void Initialize() - { - // TODO: Add your initialization logic here - - base.Initialize(); - } - - /// - /// LoadContent will be called once per game and is the place to load - /// all of your content. - /// - protected override void LoadContent() - { - // Create a new SpriteBatch, which can be used to draw textures. - spriteBatch = new SpriteBatch(GraphicsDevice); - - // TODO: use this.Content to load your game content here - } - - /// - /// UnloadContent will be called once per game and is the place to unload - /// all content. - /// - protected override void UnloadContent() - { - // TODO: Unload any non ContentManager content here - } - - /// - /// Allows the game to run logic such as updating the world, - /// checking for collisions, gathering input, and playing audio. - /// - /// Provides a snapshot of timing values. - protected override void Update(GameTime gameTime) - { - if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) - Exit(); - - // TODO: Add your update logic here - - base.Update(gameTime); - } - - /// - /// This is called when the game should draw itself. - /// - /// Provides a snapshot of timing values. - protected override void Draw(GameTime gameTime) - { - GraphicsDevice.Clear(Color.CornflowerBlue); - - // TODO: Add your drawing code here - - base.Draw(gameTime); - } - } -} diff --git a/GAME/Game_TEST/Game_TEST/Game_TEST.csproj b/GAME/Game_TEST/Game_TEST/Game_TEST.csproj deleted file mode 100644 index 7ce64010f..000000000 --- a/GAME/Game_TEST/Game_TEST/Game_TEST.csproj +++ /dev/null @@ -1,63 +0,0 @@ - - - - Debug - x86 - 8.0.30703 - 2.0 - {119DA221-3EA7-432C-AAFC-782D94EA1ECF} - WinExe - Properties - Game_TEST - Game_TEST - 512 - - - x86 - true - full - false - bin\Windows\Debug\ - DEBUG;TRACE;WINDOWS - prompt - 4 - - - x86 - pdbonly - true - bin\Windows\Release\ - TRACE;WINDOWS - prompt - 4 - - - Icon.ico - - - - - - - - - $(MSBuildExtensionsPath)\..\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll - - - - - - - - - - - - - \ No newline at end of file diff --git a/GAME/Game_TEST/Game_TEST/Icon.ico b/GAME/Game_TEST/Game_TEST/Icon.ico deleted file mode 100644 index 13be62a66..000000000 Binary files a/GAME/Game_TEST/Game_TEST/Icon.ico and /dev/null differ diff --git a/GAME/Game_TEST/Game_TEST/Program.cs b/GAME/Game_TEST/Game_TEST/Program.cs deleted file mode 100644 index b1572f623..000000000 --- a/GAME/Game_TEST/Game_TEST/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ -#region Using Statements -using System; -using System.Collections.Generic; -using System.Linq; -#endregion - -namespace Game_TEST -{ -#if WINDOWS || LINUX - /// - /// The main class. - /// - public static class Program - { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main() - { - using (var game = new Game1()) - game.Run(); - } - } -#endif -} diff --git a/GAME/Game_TEST/Game_TEST/Properties/AssemblyInfo.cs b/GAME/Game_TEST/Game_TEST/Properties/AssemblyInfo.cs deleted file mode 100644 index c1a40cb9c..000000000 --- a/GAME/Game_TEST/Game_TEST/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Game_TEST")] -[assembly: AssemblyProduct("Game_TEST")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5c4ee4ad-a4b0-483e-a8e8-4cd17cfa4c2d")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")]