-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
This commit is contained in:
RaidMax 2015-03-13 18:40:16 -05:00
parent ef80a565cb
commit 73dfb9a612
18 changed files with 812 additions and 642 deletions

View File

@ -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()
@ -29,10 +30,21 @@ 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;
}

View File

@ -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<Stats> Top = E.Owner.stats.topStats();
List<Stats> Top = E.Owner.statDB.topStats();
List<Player> TopP = new List<Player>();
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 :(");
}
}
}

View File

@ -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);
Init();
}
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<Player> findPlayers(String name)
{
String Query = String.Format("SELECT * FROM CLIENTS WHERE Name LIKE '%{0}%' LIMIT 10", name);
DataTable Result = GetDataTable(Query);
List<Player> Players = new List<Player>();
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<Ban> getBans()
{
List<Ban> Bans = new List<Ban>();
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<String, object> newPlayer = new Dictionary<String, object>();
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<Stats> topStats()
{
String Query = String.Format("SELECT * FROM STATS WHERE SKILL > '{0}' ORDER BY SKILL DESC LIMIT 4", 20);
DataTable Result = GetDataTable(Query);
List<Stats> Top = new List<Stats>();
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<String, object> updatedPlayer = new Dictionary<String, object>();
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<String, object> newBan = new Dictionary<String, object>();
newBan.Add("Reason", B.getReason());
newBan.Add("npID", B.getID());
newBan.Add("bannedByID", B.getBanner());
Insert("BANS", newBan);
}
abstract public void Init();
//HELPERS
public bool Insert(String tableName, Dictionary<String, object> data)
protected bool Insert(String tableName, Dictionary<String, object> data)
{
String columns = "";
String values = "";
@ -251,7 +45,7 @@ namespace IW4MAdmin
return returnCode;
}
public bool Update(String tableName, Dictionary<String, object> data, String where)
protected bool Update(String tableName, Dictionary<String, object> 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<Player> findPlayers(String name)
{
String Query = String.Format("SELECT * FROM CLIENTS WHERE Name LIKE '%{0}%' LIMIT 8", name);
DataTable Result = GetDataTable(Query);
List<Player> Players = new List<Player>();
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<Ban> getBans()
{
List<Ban> Bans = new List<Ban>();
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<String, object> newPlayer = new Dictionary<String, object>();
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<String, Object> updatedPlayer = new Dictionary<String, Object>();
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<String, object> newBan = new Dictionary<String, object>();
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<String, object> newPlayer = new Dictionary<String, object>();
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<String, object> updatedPlayer = new Dictionary<String, object>();
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<Stats> topStats()
{
String Query = String.Format("SELECT * FROM STATS WHERE SKILL > '{0}' ORDER BY SKILL DESC LIMIT 8", 20);
DataTable Result = GetDataTable(Query);
List<Stats> Top = new List<Stats>();
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<String, Object> () { {"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<String, object> newPlayer = new Dictionary<String, object>();
newPlayer.Add("Number", Alias.getNumber());
newPlayer.Add("NAMES", Alias.getNamesDB());
newPlayer.Add("IPS", Alias.getIPSDB());
Insert("ALIASES", newPlayer);
}
public void updatePlayer(Aliases Alias)
{
Dictionary<String, object> updatedPlayer = new Dictionary<String, object>();
updatedPlayer.Add("Number", Alias.getNumber());
updatedPlayer.Add("NAMES", Alias.getNamesDB());
updatedPlayer.Add("IPS", Alias.getIPSDB());
Update("ALIASES", updatedPlayer, String.Format("Number = '{0}'", Alias.getNumber()));
}
}
}

View File

@ -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);
}

View File

@ -28,7 +28,7 @@
<PublisherName>RaidMax LLC</PublisherName>
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>publish.htm</WebPage>
<ApplicationRevision>5</ApplicationRevision>
<ApplicationRevision>6</ApplicationRevision>
<ApplicationVersion>0.4.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>

View File

@ -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)

View File

@ -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<String> getNames()
{
return new List<String>(Names.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
}
public List<String> getIPS()
{
return new List<String>(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;
}
}

View File

@ -22,52 +22,17 @@ namespace IW4MAdmin
sv_connection.Client.SendTimeout = 1000;
sv_connection.Client.ReceiveTimeout = 1000;
Instance = I;
toSend = new Queue<String>();
toSend = new Queue<RCON_Request>();
}
//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");
@ -89,32 +54,49 @@ namespace IW4MAdmin
sv_connection.Connect(endPoint);
sv_connection.Send(Request, Request.Length);
String incoming = String.Empty;
byte[] bufferRecv = new byte[65536];
do
{
// loop on receiving the bytes
bufferRecv = sv_connection.Receive(ref endPoint);
// only decode the bytes received
incoming += (Encoding.ASCII.GetString(bufferRecv, 0, bufferRecv.Length));
} while (sv_connection.Available > 0);
Byte[] receive = sv_connection.Receive(ref endPoint);
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
String[] response = System.Text.Encoding.UTF8.GetString(receive).Split((char)num);
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<String> toSend;
private Queue<RCON_Request> 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;
}
}

View File

@ -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<Player>(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<Map>();
rules = new List<String>();
messages = new List<String>();
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<Event>();
HB = new Heartbeat(this);
Macros = new Dictionary<String, Object>();
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)
{
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 A;
A = DB.getPlayer(P.getID(), P.getClientNum());
if (A.getName() != P.getName())
A.updateName(P.getName());
A.lastEvent = P.lastEvent;
P = A;
}
P.stats = stats.getStats(P.getDBID());
if (P.stats == null)
Player NewPlayer = clientDB.getPlayer(P.getID(), P.getClientNum());
NewPlayer.stats = statDB.getStats(NewPlayer.getDBID());
if (NewPlayer.stats == null)
{
stats.addPlayer(P);
P.stats = new Stats(0, 0, 0, 1);
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());
}
if(players[P.getClientNum()] == null)
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--;
@ -196,19 +234,39 @@ 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<string, string> 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,6 +340,11 @@ namespace IW4MAdmin
//Starts the monitoring process
public void Monitor()
{
//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);
@ -289,15 +352,11 @@ namespace IW4MAdmin
return;
}
//Handles new rcon requests in a fashionable manner
Thread RCONQueue = new Thread(new ThreadStart(RCON.ManageRCONQueue));
RCONQueue.Start();
//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,12 +372,23 @@ 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;
if (timesFailed <= 3)
HB.Send();
}
@ -387,7 +457,7 @@ namespace IW4MAdmin
{
try
{
String[] infoResponse = RCON.responseSendRCON("getstatus");
String[] infoResponse = RCON.addRCON("getstatus");
if (infoResponse == null || infoResponse.Length < 2)
{
@ -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<String, String> infoResponseDict = new Dictionary<string, string>();
//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<String>();
maps = new List<Map>();
rules = new List<String>();
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<String, Object>();
Macros.Add("WISDOM", Wisdom());
Macros.Add("TOTALPLAYERS", clientDB.totalPlayers());
}
private void initMaps()
{
maps = new List<Map>();
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<String>();
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<String>();
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 <player> <reason>.", "w", Player.Permission.Moderator, 2, true));
commands.Add(new WarnClear("warnclear", "remove all warning for a player syntax: !warnclear <player>.", "wc", Player.Permission.Administrator, 1, true));
commands.Add(new Unban("unban", "unban player by guid. syntax: !unban <guid>.", "ub", Player.Permission.Administrator, 1, true));
commands.Add(new Unban("unban", "unban player by guid. syntax: !unban <guid>.", "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 <player>", "f", Player.Permission.Administrator, 1, false));
commands.Add(new Find("find", "find player in database. syntax: !find <player>", "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 <player> <message>", "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 <number>", 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<Ban> Bans;
public Player owner;
public List<Map> maps;
public List<String> rules;
public Queue<Event> 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<String, Object> Macros;
//Will probably move this later
private Dictionary<String, String> IPS;
//Log stuff

View File

@ -57,7 +57,7 @@ namespace IW4MAdmin
public static String removeNastyChars(String str)
{
return str.Replace("`", "").Replace("'", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace("&quot;", "''");
return str.Replace("`", "").Replace("\\", "").Replace("\"", "").Replace("^", "").Replace("&quot;", "''").Replace("&amp;", "&").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;
}
}
public static String processMacro(Dictionary<String, Object> 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<String, String> IPFromStatus(String[] players)
{
Dictionary<String, String> Dict = new Dictionary<String, String>();
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);
}
}
}

View File

@ -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?

View File

@ -1 +1,11 @@
0.4
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

View File

@ -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

View File

@ -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
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1()
: base()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// 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.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
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
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
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);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}

View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{119DA221-3EA7-432C-AAFC-782D94EA1ECF}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Game_TEST</RootNamespace>
<AssemblyName>Game_TEST</AssemblyName>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Windows\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Windows\Release\</OutputPath>
<DefineConstants>TRACE;WINDOWS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Compile Include="Game1.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="MonoGame.Framework">
<HintPath>$(MSBuildExtensionsPath)\..\MonoGame\v3.0\Assemblies\Windows\MonoGame.Framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Content Include="Icon.ico" />
</ItemGroup>
<ItemGroup>
<Folder Include="Content\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,26 +0,0 @@
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
#endregion
namespace Game_TEST
{
#if WINDOWS || LINUX
/// <summary>
/// The main class.
/// </summary>
public static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (var game = new Game1())
game.Run();
}
}
#endif
}

View File

@ -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")]