diff --git a/Admin/Command.cs b/Admin/Command.cs index 2c831c5bf..b21cc794e 100644 --- a/Admin/Command.cs +++ b/Admin/Command.cs @@ -467,6 +467,7 @@ namespace IW4MAdmin public override void Execute(Event E) { + E.Data = Utilities.removeWords(E.Data, 1); E.Target.Tell("^1" + E.Origin.getName() + " ^3[PM]^7 - " + E.Data); E.Origin.Tell(String.Format("To ^3{0} ^7-> {1}", E.Target.getName(), E.Data)); } diff --git a/Admin/Database.cs b/Admin/Database.cs index 3dfb6c05a..e4a7e4508 100644 --- a/Admin/Database.cs +++ b/Admin/Database.cs @@ -350,7 +350,7 @@ namespace IW4MAdmin //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); + String Query = String.Format("SELECT * FROM STATS WHERE SKILL > '{0}' ORDER BY SKILL DESC LIMIT 8", 10); DataTable Result = GetDataTable(Query); List Top = new List(); @@ -360,7 +360,7 @@ namespace IW4MAdmin 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) + if (S.Skill > 10) Top.Add(S); } } diff --git a/Admin/Event.cs b/Admin/Event.cs index c6a92255b..f2afebff2 100644 --- a/Admin/Event.cs +++ b/Admin/Event.cs @@ -58,7 +58,9 @@ namespace IW4MAdmin public static Event requestEvent(String[] line, Server SV) { +#if DEBUG == false try +#endif { String eventType = line[0].Substring(line[0].Length - 1); eventType = eventType.Trim(); @@ -76,7 +78,7 @@ namespace IW4MAdmin { if (line.Length < 4) { - Console.WriteLine("SAY FUCKED UP"); + Console.WriteLine("SAY FUCKED UP BIG-TIME"); return null; } Regex rgx = new Regex("[^a-zA-Z0-9 -! -_]"); @@ -93,11 +95,13 @@ namespace IW4MAdmin return null; } +#if DEBUG == false catch (Exception E) { SV.Log.Write("Error requesting event " + E.Message, Log.Level.Debug); return null; } +#endif } diff --git a/Admin/File.cs b/Admin/File.cs index c4cd735cb..98fd3f3fa 100644 --- a/Admin/File.cs +++ b/Admin/File.cs @@ -29,6 +29,7 @@ namespace IW4MAdmin { Name = file; writeHandle = new StreamWriter(new FileStream(Name, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); + // writeHandle.AutoFlush = true; sze = 0; } diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj index d75e9be0a..696ee25a8 100644 --- a/Admin/IW4M ADMIN.csproj +++ b/Admin/IW4M ADMIN.csproj @@ -28,8 +28,8 @@ RaidMax LLC true publish.htm - 6 - 0.4.0.%2a + 7 + 0.6.0.%2a false true true diff --git a/Admin/Main.cs b/Admin/Main.cs index 74a5e4fc6..3406c4c52 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.5; + static public double Version = 0.6; static public double latestVersion; static void Main(string[] args) diff --git a/Admin/Player.cs b/Admin/Player.cs index 3b27d8df7..bed847841 100644 --- a/Admin/Player.cs +++ b/Admin/Player.cs @@ -100,7 +100,10 @@ namespace IW4MAdmin Level = (Player.Permission)l; LastOffense = null; Connections = 0; + IP = ""; Warnings = 0; + Alias = new Aliases(0, "", ""); + stats = new Stats(0, 0, 0, 1); } public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2) diff --git a/Admin/RCON.cs b/Admin/RCON.cs index 701a2e98b..ddeacd696 100644 --- a/Admin/RCON.cs +++ b/Admin/RCON.cs @@ -101,7 +101,7 @@ namespace IW4MAdmin public void ManageRCONQueue() { - while (true) + while (Instance.isRunning) { if (toSend.Count > 0) { diff --git a/Admin/Server.cs b/Admin/Server.cs index 399b6904f..f08381b4d 100644 --- a/Admin/Server.cs +++ b/Admin/Server.cs @@ -99,11 +99,72 @@ namespace IW4MAdmin { return Bans; } + + public void threadedConnect(Player P, Player NewPlayer) + { + bool updated = false; + while (!updated) + { + try + { + P.updateIP(IPS[P.getID()].Trim()); + updated = true; + Log.Write("Sucessfully updated " + NewPlayer.getName() + "'s IP to " + P.getIP(), Log.Level.Debug); + } + + catch + { + //Log.Write("Looks like the connecting player doesn't have an IP location assigned yet. Let's wait for next poll", Log.Level.Debug); + Utilities.Wait(1); + } + } + + if (NewPlayer.Alias == null) + { + aliasDB.addPlayer(new Aliases(NewPlayer.getDBID(), NewPlayer.getName(), P.getIP())); + } + + if (P.getName() != NewPlayer.getName()) + { + NewPlayer.updateName(P.getName()); + NewPlayer.Alias.addName(P.getName()); + aliasDB.updatePlayer(NewPlayer.Alias); + } + + if (P.getIP() != NewPlayer.getIP()) + { + NewPlayer.updateIP(P.getIP()); + NewPlayer.Alias.addIP(P.getIP()); + aliasDB.updatePlayer(NewPlayer.Alias); + } + + clientDB.updatePlayer(NewPlayer); + + Ban B = isBanned(NewPlayer); + if (B != null || NewPlayer.getLevel() == Player.Permission.Banned) + { + Log.Write("Banned client " + P.getName() + " trying to connect...", Log.Level.Debug); + string Reason = String.Empty; + if (B != null) + Reason = B.getReason(); + else + Reason = P.LastOffense; + + String Message = "^1Player Kicked: ^7Previously Banned for ^5" + Reason; + P.Kick(Message); + } + + players[NewPlayer.getClientNum()] = null; + players[NewPlayer.getClientNum()] = NewPlayer; + + } //Add player object p to `players` list public bool addPlayer(Player P) { +#if DEBUG == false try +#endif { if (clientDB.getPlayer(P.getID(), P.getClientNum()) == null) { @@ -117,68 +178,38 @@ namespace IW4MAdmin //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) + NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.getDBID()); + + if (NewPlayer.stats == null) //For safety { statDB.addPlayer(NewPlayer); NewPlayer.stats = statDB.getStats(NewPlayer.getDBID()); } - NewPlayer.Alias = aliasDB.getPlayer(NewPlayer.getDBID()); - NewPlayer.lastEvent = P.lastEvent; - + + if (P.lastEvent == null) + NewPlayer.lastEvent = new Event(Event.GType.Say, null, NewPlayer, null, this); // this is messy but its throwing an error when they've started it too late + else + 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()); - } + Thread connectThread = new Thread(() => threadedConnect(P, NewPlayer)); + connectThread.Start(); // We don't want events to get behind + NewPlayer.Tell("Welcome ^5" + NewPlayer.getName() + " ^7this is your ^5" + Utilities.timesConnected(NewPlayer.getConnections()) + " ^7time connecting!"); + Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); clientnum++; } - NewPlayer.lastEvent = P.lastEvent; - - 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" + B.getReason(); - P.Kick(Message); - } - - else - Log.Write("Client " + NewPlayer.getName() + " connecting...", Log.Level.Debug); - - clientDB.updatePlayer(NewPlayer); - aliasDB.updatePlayer(NewPlayer.Alias); - return true; } +#if DEBUG == false catch (Exception E) { Log.Write("Unable to add player " + P.getName() + " - " + E.Message, Log.Level.Debug); return false; } +#endif } //Remove player by CLIENT NUMBER @@ -214,7 +245,8 @@ namespace IW4MAdmin } Log.Write("Could not find player but player is in server. Lets try to manually add (looks like you didn't start me on an empty server)", Log.Level.All); - addPlayer(new Player(Name, line[1].ToString(), Convert.ToInt16(line[2]), 0)); + players[Convert.ToInt16(line[2])] = null; + addPlayer(new Player(Name, line[1].ToString().Trim(), Convert.ToInt16(line[2]), 0)); return players[Convert.ToInt16(line[2])]; } } @@ -326,7 +358,7 @@ namespace IW4MAdmin private void manageEventQueue() { - while (true) + while (isRunning) { if (events.Count > 0) { @@ -340,6 +372,7 @@ namespace IW4MAdmin //Starts the monitoring process public void Monitor() { + isRunning = true; //Handles new rcon requests in a fashionable manner Thread RCONQueue = new Thread(new ThreadStart(RCON.ManageRCONQueue)); @@ -348,32 +381,41 @@ namespace IW4MAdmin if (!intializeBasics()) { Log.Write("Stopping " + Port + " due to uncorrectable errors (check log)" + logPath, Log.Level.Production); - Utilities.Wait(10); + isRunning = false; + Utilities.Wait(10); return; } + Thread statusUpdate = new Thread(new ThreadStart(pollServer)); + statusUpdate.Start(); + //Handles new events in a fashionable manner Thread eventQueue = new Thread(new ThreadStart(manageEventQueue)); eventQueue.Start(); int timesFailed = 0; long l_size = -1; + bool checkedForOutdate = false; String[] lines = new String[8]; String[] oldLines = new String[8]; DateTime start = DateTime.Now; Utilities.Wait(1); +#if DEBUG == false Broadcast("IW4M Admin is now ^2ONLINE"); +#endif while (errors <=5) { - try +#if DEBUG == false + try +#endif { lastMessage = DateTime.Now - start; if(lastMessage.TotalSeconds > messageTime && messages.Count > 0) { - if (RCON.responseSendRCON("sv_online") == null) + if (RCON.addRCON("sv_online") == null) { timesFailed++; Log.Write("Server appears to be offline - " + timesFailed, Log.Level.Debug); @@ -381,7 +423,7 @@ namespace IW4MAdmin else timesFailed = 0; Thread.Sleep(300); - initMacros(); + initMacros(); // somethings dynamically change so we have to re-init the dictionary Broadcast(Utilities.processMacro(Macros, messages[nextMessage])); if (nextMessage == (messages.Count - 1)) nextMessage = 0; @@ -390,6 +432,16 @@ namespace IW4MAdmin start = DateTime.Now; if (timesFailed <= 3) HB.Send(); + + String checkVer = new Connection("http://raidmax.org/IW4M/Admin/version.php").Read(); + double checkVerNum; + double.TryParse(checkVer, out checkVerNum); + if (checkVerNum != Program.Version && checkVerNum != 0 && !checkedForOutdate) + { + messages.Add("^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + checkVerNum); + checkedForOutdate = true; + } + } if (l_size != logFile.getSize()) @@ -438,20 +490,38 @@ namespace IW4MAdmin l_size = logFile.getSize(); Thread.Sleep(1); } +#if DEBUG == false catch (Exception E) { Log.Write("Something unexpected occured. Hopefully we can ignore it - " + E.Message + " @" + Utilities.GetLineNumber(E), Log.Level.All); errors++; continue; } +#endif } - + isRunning = false; RCONQueue.Abort(); eventQueue.Abort(); } + private void pollServer() + { + while (isRunning) + { + IPS = Utilities.IPFromStatus(RCON.addRCON("status")); + while (IPS == null) + { + IPS = Utilities.IPFromStatus(RCON.addRCON("status")); + Utilities.Wait(1); + } + + lastPoll = DateTime.Now; + Utilities.Wait(15); + } + } + //Vital RCON commands to establish log file and server name. May need to cleanup in the future private bool intializeBasics() { @@ -513,7 +583,7 @@ namespace IW4MAdmin //END //get fs_game - p =RCON.addRCON("fs_game"); + p = RCON.addRCON("fs_game"); if (p == null) { @@ -550,7 +620,7 @@ namespace IW4MAdmin //END //get g_logsync - p =RCON.addRCON("g_logsync"); + p = RCON.addRCON("g_logsync"); if (p == null) { @@ -595,8 +665,8 @@ namespace IW4MAdmin logFile = new file(logPath); Log.Write("Log file is " + logPath, Log.Level.Debug); - //get players ip's - p =RCON.addRCON("status"); + //get players ip's + p = RCON.addRCON("status"); if (p == null) { Log.Write("Unable to get initial player list!", Log.Level.Debug); @@ -604,6 +674,7 @@ namespace IW4MAdmin } IPS = Utilities.IPFromStatus(p); + lastPoll = DateTime.Now; #if DEBUG /* System.Net.FtpWebRequest tmp = (System.Net.FtpWebRequest)System.Net.FtpWebRequest.Create("ftp://raidmax.org/logs/games_old.log"); @@ -612,7 +683,6 @@ namespace IW4MAdmin String ftpLog = new StreamReader(ftpStream).ReadToEnd();*/ logPath = "games_old.log"; #endif - return true; } catch (Exception E) @@ -978,6 +1048,8 @@ namespace IW4MAdmin //Will probably move this later private Dictionary IPS; + public bool isRunning; + private DateTime lastPoll; //Log stuff diff --git a/Admin/Utilities.cs b/Admin/Utilities.cs index b954826b7..7acc14c18 100644 --- a/Admin/Utilities.cs +++ b/Admin/Utilities.cs @@ -113,6 +113,9 @@ namespace IW4MAdmin { Dictionary Dict = new Dictionary(); + if (players == null) + return null; + foreach (String S in players) { String S2 = S.Trim(); @@ -141,5 +144,47 @@ namespace IW4MAdmin 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); } + + public static String timesConnected(int connection) + { + String Prefix = String.Empty; + if (connection % 10 > 3 || connection % 10 == 0) + Prefix = "th"; + else + { + switch (connection % 10) + { + case 1: + Prefix = "st"; + break; + case 2: + Prefix = "nd"; + break; + case 3: + Prefix = "rd"; + break; + } + + } + + switch (connection) + { + case 0: + case 1: + return "first"; + case 2: + return "second"; + case 3: + return "third"; + case 4: + return "fourth"; + case 5: + return "fifth"; + case 100: + return "One-Hundreth (amazing!)"; + default: + return connection.ToString() + Prefix; + } + } } } diff --git a/Admin/version.txt b/Admin/version.txt index 7d837fb93..3be8ba2c6 100644 --- a/Admin/version.txt +++ b/Admin/version.txt @@ -1,11 +1,4 @@ -VERSION: 0.5 +VERSION: 0.6 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 +-stability fixes +-welcome has post-fixed connection indicator