diff --git a/Admin/Command.cs b/Admin/Command.cs
index 15674f2db..9fac290ee 100644
--- a/Admin/Command.cs
+++ b/Admin/Command.cs
@@ -167,7 +167,11 @@ namespace IW4MAdmin
{
E.Target.LastOffense = Utilities.removeWords(E.Data, 1);
E.Target.lastEvent = E; // needs to be fixed
+#if DEBUG
String Message = "^1Player Banned: ^5" + E.Target.LastOffense + "^7 (appeal at nbsclan.org)";
+#else
+ String Message = "^1Player Banned: ^5" + E.Target.LastOffense;
+#endif
if (E.Origin.getLevel() > E.Target.getLevel())
{
E.Target.Ban(Message, E.Origin);
diff --git a/Admin/Connection.cs b/Admin/Connection.cs
index 3c5a3dacd..f970f446c 100644
--- a/Admin/Connection.cs
+++ b/Admin/Connection.cs
@@ -35,6 +35,20 @@ namespace IW4MAdmin
}
}
+ public void Request(String data)
+ {
+ try
+ {
+ WebResponse Resp = WebRequest.Create(data).GetResponse();
+ Resp.Close();
+ }
+
+ catch (System.Net.WebException E)
+ {
+ return;
+ }
+ }
+
private String Location;
private WebRequest ConnectionHandle;
}
diff --git a/Admin/Database.cs b/Admin/Database.cs
index 0d78b3e22..e1c0cd6c8 100644
--- a/Admin/Database.cs
+++ b/Admin/Database.cs
@@ -187,7 +187,7 @@ namespace IW4MAdmin
{
updatedPlayer.Add("KILLS", P.stats.Kills);
updatedPlayer.Add("DEATHS", P.stats.Deaths);
- updatedPlayer.Add("KDR", P.stats.KDR);
+ updatedPlayer.Add("KDR", Math.Round(P.stats.KDR, 2));
updatedPlayer.Add("SKILL", P.stats.Skill);
Update("STATS", updatedPlayer, String.Format("Number = '{0}'", P.getDBID()));
diff --git a/Admin/Event.cs b/Admin/Event.cs
index 35fdef7ab..c6a92255b 100644
--- a/Admin/Event.cs
+++ b/Admin/Event.cs
@@ -84,11 +84,11 @@ namespace IW4MAdmin
return new Event(GType.Say, Utilities.removeNastyChars(message), SV.clientFromLine(line, 3, false), null, null);
}
- if (eventType == "d" || eventType == ":")
+ if (eventType == ":")
return new Event(GType.MapEnd, null, null, null, null);
if (line[0].Length > 400) // blaze it
- return new Event(GType.MapChange, null, null, null, null);
+ return new Event(GType.MapChange, line[0], null, null, null);
return null;
diff --git a/Admin/File.cs b/Admin/File.cs
index fe953005b..c4cd735cb 100644
--- a/Admin/File.cs
+++ b/Admin/File.cs
@@ -64,6 +64,14 @@ namespace IW4MAdmin
return 0;
}
+ public void Close()
+ {
+ if(Handle != null)
+ Handle.Close();
+ if (writeHandle != null)
+ writeHandle.Close();
+ }
+
//FROM http://stackoverflow.com/questions/398378/get-last-10-lines-of-very-large-text-file-10gb-c-sharp
public string ReadEndTokens()
{
@@ -105,7 +113,7 @@ namespace IW4MAdmin
}
public String[] readAll()
{
- return Handle.ReadToEnd().Split('\n');
+ return Handle.ReadToEnd().Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
public String[] end(int neededLines)
diff --git a/Admin/Heartbeat.cs b/Admin/Heartbeat.cs
new file mode 100644
index 000000000..4f94ca0bc
--- /dev/null
+++ b/Admin/Heartbeat.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IW4MAdmin
+{
+ class Heartbeat
+ {
+ public Heartbeat(Server I)
+ {
+ Handle = new Connection("http://raidmax.org/IW4M/Admin");
+ Instance = I;
+ }
+
+ 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());
+ Handle.Request(URI);
+ }
+
+ private Connection Handle;
+ private Server Instance;
+ }
+}
diff --git a/Admin/IW4M ADMIN.csproj b/Admin/IW4M ADMIN.csproj
index 4878af297..4a817a6ed 100644
--- a/Admin/IW4M ADMIN.csproj
+++ b/Admin/IW4M ADMIN.csproj
@@ -94,6 +94,7 @@
+
diff --git a/Admin/Main.cs b/Admin/Main.cs
index b1c8f3be4..b9394866a 100644
--- a/Admin/Main.cs
+++ b/Admin/Main.cs
@@ -24,57 +24,40 @@ namespace IW4MAdmin
else
Console.WriteLine(" Version " + Version + " (unable to retrieve latest)");
Console.WriteLine("=====================================================");
+
+
+ foreach (Server IW4M in checkConfig())
+ {
+ //Threading seems best here
+ Thread monitorThread = new Thread(new ThreadStart(IW4M.Monitor));
+ monitorThread.Start();
+ Utilities.Wait(0.3);
+ Console.WriteLine("Now monitoring " + IW4M.getName());
+ }
+
+ Utilities.Wait(5); //Give them time to read an error before exiting
-
- file Config = new file("config\\servers.cfg");
- String[] SV_CONF = Config.readAll();
-
- if (SV_CONF == null || SV_CONF.Length < 1 || SV_CONF[0] == String.Empty)
- {
- setupConfig();
- SV_CONF = new file("config\\servers.cfg").readAll();
- }
-
-
- if (Config.getSize() > 0 && SV_CONF != null)
- {
- foreach (String S in SV_CONF)
- {
- if (S.Length < 1)
- continue;
-
- String[] sv = S.Split(':');
-
- Console.WriteLine("Starting admin on port " + sv[1]);
-
- Server IW4M;
- IW4M = new Server(sv[0], Convert.ToInt32(sv[1]), sv[2]);
-
- //Threading seems best here
- Thread monitorThread = new Thread(new ThreadStart(IW4M.Monitor));
- monitorThread.Start();
- }
-
- }
- else
- {
- Console.WriteLine("[FATAL] CONFIG FILE DOES NOT EXIST OR IS INCORRECT!");
- Utilities.Wait(5);
- }
-
}
static void setupConfig()
{
+ bool validPort = false;
Console.WriteLine("Hey there, it looks like you haven't set up a server yet. Let's get started!");
+
Console.Write("Please enter the IP: ");
IP = Console.ReadLine();
- Console.Write("Please enter the Port: ");
- Port = Convert.ToInt32(Console.ReadLine());
+
+ while (!validPort)
+ {
+ Console.Write("Please enter the Port: ");
+ int.TryParse(Console.ReadLine(), out Port);
+ if (Port != 0)
+ validPort = true;
+ }
+
Console.Write("Please enter the RCON password: ");
RCON = Console.ReadLine();
file Config = new file("config\\servers.cfg", true);
- Config.Write(IP + ":" + Port + ":" + RCON);
Console.WriteLine("Great! Let's go ahead and start 'er up.");
}
@@ -83,5 +66,38 @@ namespace IW4MAdmin
Connection Ver = new Connection("http://raidmax.org/IW4M/Admin/version.php");
return Ver.Read();
}
+
+ static List checkConfig()
+ {
+
+ file Config = new file("config\\servers.cfg");
+ String[] SV_CONF = Config.readAll();
+ List Servers = new List();
+
+
+ if (SV_CONF == null || SV_CONF.Length < 1 || SV_CONF[0] == String.Empty)
+ {
+ setupConfig(); // get our first time server
+ Config.Write(IP + ':' + Port + ':' + RCON);
+ Servers.Add(new Server(IP, Port, RCON));
+ }
+
+ else
+ {
+ foreach (String L in SV_CONF)
+ {
+ String[] server_line = L.Split(':');
+ int newPort;
+ if (server_line.Length < 3 || !int.TryParse(server_line[1], out newPort))
+ {
+ Console.WriteLine("You have an error in your server.cfg");
+ continue;
+ }
+ Servers.Add(new Server(server_line[0], newPort, server_line[2]));
+ }
+ }
+
+ return Servers;
+ }
}
}
diff --git a/Admin/Player.cs b/Admin/Player.cs
index 5b90389de..e5c8f76d6 100644
--- a/Admin/Player.cs
+++ b/Admin/Player.cs
@@ -10,7 +10,7 @@ namespace IW4MAdmin
{
Kills = K;
Deaths = D;
- KDR = kdr;
+ KDR = Math.Round(kdr,2);
Skill = Math.Round(skill,2);
}
diff --git a/Admin/RCON.cs b/Admin/RCON.cs
index d62eaf178..b9cb6c0df 100644
--- a/Admin/RCON.cs
+++ b/Admin/RCON.cs
@@ -67,7 +67,7 @@ namespace IW4MAdmin
{
String STR_REQUEST;
if (message != "getstatus")
- STR_REQUEST = String.Format("ÿÿÿÿrcon {0} {1}", Instance.getPassword(), message);
+ STR_REQUEST = String.Format("ÿÿÿÿrcon {0} {1}", Instance.getPassword().Replace("\r", String.Empty), message);
else
STR_REQUEST = String.Format("ÿÿÿÿ getstatus");
@@ -93,7 +93,15 @@ namespace IW4MAdmin
Byte[] receive = sv_connection.Receive(ref endPoint);
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
- return System.Text.Encoding.UTF8.GetString(receive).Split((char)num);
+ String[] response = System.Text.Encoding.UTF8.GetString(receive).Split((char)num);
+
+ if(response[1] == "Invalid password.")
+ {
+ Instance.Log.Write("Invalid RCON password specified", Log.Level.Debug);
+ return null;
+ }
+
+ return response;
}
catch (SocketException)
diff --git a/Admin/Server.cs b/Admin/Server.cs
index d2a8f6871..d61e0ddfb 100644
--- a/Admin/Server.cs
+++ b/Admin/Server.cs
@@ -30,6 +30,7 @@ namespace IW4MAdmin
rules = new List();
messages = new List();
events = new Queue();
+ HB = new Heartbeat(this);
nextMessage = 0;
initCommands();
initMessages();
@@ -43,6 +44,11 @@ namespace IW4MAdmin
return hostname;
}
+ public String getMap()
+ {
+ return mapname;
+ }
+
//Returns current server IP set by `net_ip` -- *STRING*
public String getIP()
{
@@ -73,6 +79,11 @@ namespace IW4MAdmin
return players;
}
+ public int getClientNum()
+ {
+ return clientnum;
+ }
+
//Returns list of all active bans (loaded at runtime)
public List getBans()
{
@@ -282,8 +293,8 @@ namespace IW4MAdmin
String[] oldLines = new String[8];
DateTime start = DateTime.Now;
- Utilities.Wait(1);
- Broadcast("IW4M Admin is now ^2ONLINE");
+ //Utilities.Wait(1);
+ //Broadcast("IW4M Admin is now ^2ONLINE");
while (errors <=5)
{
@@ -292,14 +303,13 @@ namespace IW4MAdmin
lastMessage = DateTime.Now - start;
if(lastMessage.TotalSeconds > messageTime && messages.Count > 0)
{
- if (Program.Version != Program.latestVersion && Program.latestVersion != 0)
- Broadcast("^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + Program.latestVersion);
Broadcast(messages[nextMessage]);
if (nextMessage == (messages.Count - 1))
nextMessage = 0;
else
nextMessage++;
start = DateTime.Now;
+ HB.Send();
}
if (l_size != logFile.getSize())
@@ -367,8 +377,40 @@ namespace IW4MAdmin
{
try
{
+ //get sv_hostname
+ String[] p = RCON.responseSendRCON("sv_hostname");
+
+ if (p == null)
+ {
+ Log.Write("Could not obtain server name!", Log.Level.All);
+ return false;
+ }
+
+ p = p[1].Split('"');
+ hostname = Utilities.stripColors(p[3].Substring(0, p[3].Length - 2).Trim());
+ p = null;
+ //END
+
+ Thread.Sleep(FLOOD_TIMEOUT);
+
+ //get mapname
+ p = RCON.responseSendRCON("mapname");
+
+ if (p == null)
+ {
+ Log.Write("Could not obtain map name!", Log.Level.All);
+ return false;
+ }
+
+ p = p[1].Split('"');
+ mapname = Utilities.stripColors(p[3].Substring(0, p[3].Length - 2).Trim());
+ p = null;
+ //END
+
+ Thread.Sleep(FLOOD_TIMEOUT);
+
//GET fs_basepath
- String[] p = RCON.responseSendRCON("fs_basepath");
+ p = RCON.responseSendRCON("fs_basepath");
if (p == null)
{
@@ -459,20 +501,6 @@ namespace IW4MAdmin
Thread.Sleep(FLOOD_TIMEOUT);
- //get sv_hostname
- p = RCON.responseSendRCON("sv_hostname");
-
- if (p == null)
- {
- Log.Write("Could not obtain server name!", Log.Level.All);
- return false;
- }
-
- p = p[1].Split('"');
- hostname = p[3].Substring(0, p[3].Length - 2).Trim();
- p = null;
- //END
-
if (Mod == String.Empty || onelog == "1")
logPath = Basepath + '\\' + "m2demo" + '\\' + log;
else
@@ -501,13 +529,13 @@ namespace IW4MAdmin
{
if (E.Type == Event.GType.Connect)
{
- this.addPlayer(E.Origin);
+ addPlayer(E.Origin);
return true;
}
if (E.Type == Event.GType.Disconnect)
{
- if (getNumPlayers() > 0)
+ if (getNumPlayers() > 0 && E.Origin != null)
{
DB.updatePlayer(E.Origin);
stats.updatePlayer(E.Origin);
@@ -518,7 +546,7 @@ namespace IW4MAdmin
if (E.Type == Event.GType.Kill)
{
- if (E.Origin != null && E.Target != null)
+ if (E.Origin != null && E.Target != null && E.Origin.stats != null)
{
E.Origin.stats.Kills++;
E.Origin.stats.Update();
@@ -527,7 +555,7 @@ namespace IW4MAdmin
}
}
- if (E.Type == Event.GType.Say)
+ if (E.Type == Event.GType.Say && E.Origin != null)
{
if (E.Data.Length < 2)
return false;
@@ -561,17 +589,18 @@ namespace IW4MAdmin
if (E.Type == Event.GType.MapChange)
{
- Log.Write("Map change detected..", Log.Level.Production);
- return true;
- //TODO here
+ Log.Write("New map loaded", Log.Level.Debug);
+ String[] statusResponse = E.Data.Split('\\');
+ if (statusResponse.Length >= 15 && statusResponse[13] == "mapname")
+ mapname = maps.Find(m => m.Name.Equals(statusResponse[14])).Alias; //update map for heartbeat
}
if (E.Type == Event.GType.MapEnd)
{
- Log.Write("Game ending...", Log.Level.Production);
+ Log.Write("Game ending...", Log.Level.Debug);
foreach (Player P in players)
{
- if (P == null)
+ if (P == null || P.stats == null)
continue;
stats.updatePlayer(P);
Log.Write("Updated stats for client " + P.getDBID(), Log.Level.Debug);
@@ -707,6 +736,8 @@ namespace IW4MAdmin
if (lines[0] != l && l.Length > 1)
messages.Add(l);
}
+ if (Program.Version != Program.latestVersion && Program.latestVersion != 0)
+ messages.Add("^5IW4M Admin ^7is outdated. Please ^5update ^7to version " + Program.latestVersion);
}
private void initRules()
@@ -740,11 +771,11 @@ namespace IW4MAdmin
commands.Add(new SBan("ban", "permanently ban a player from the server. syntax: !ban ", "b", Player.Permission.SeniorAdmin, 2, true));
commands.Add(new WhoAmI("whoami", "give information about yourself. syntax: !whoami.", "who", Player.Permission.User, 0, false));
commands.Add(new List("list", "list active clients syntax: !list.", "l", Player.Permission.Moderator, 0, false));
- commands.Add(new Help("help", "list all available commands. syntax: !help.", "l", Player.Permission.User, 0, false));
+ commands.Add(new Help("help", "list all available commands. syntax: !help.", "h", Player.Permission.User, 0, false));
commands.Add(new FastRestart("fastrestart", "fast restart current map. syntax: !fastrestart.", "fr", Player.Permission.Moderator, 0, false));
commands.Add(new MapRotate("maprotate", "cycle to the next map in rotation. syntax: !maprotate.", "mr", Player.Permission.Administrator, 0, false));
commands.Add(new SetLevel("setlevel", "set player to specified administration level. syntax: !setlevel .", "sl", Player.Permission.Owner, 2, true));
- commands.Add(new Usage("usage", "get current application memory usage. syntax: !usage.", "u", Player.Permission.Moderator, 0, false));
+ commands.Add(new Usage("usage", "get current application memory usage. syntax: !usage.", "us", Player.Permission.Moderator, 0, false));
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));
@@ -774,11 +805,13 @@ namespace IW4MAdmin
public List rules;
public Queue events;
public Database stats;
+ public Heartbeat HB;
//Info
private String IP;
private int Port;
private String hostname;
+ private String mapname;
private int clientnum;
private string rcon_pass;
private List players;
@@ -788,6 +821,7 @@ namespace IW4MAdmin
private TimeSpan lastMessage;
private int nextMessage;
private int errors = 0;
+ private Connection Heartbeat;
//Log stuff
private String Basepath;
diff --git a/Admin/Utilities.cs b/Admin/Utilities.cs
index 3c4aecb82..301ac3d54 100644
--- a/Admin/Utilities.cs
+++ b/Admin/Utilities.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Threading;
+using System.Text.RegularExpressions;
namespace IW4MAdmin
{
@@ -73,5 +74,10 @@ namespace IW4MAdmin
}
return lineNumber;
}
+
+ public static String stripColors(String str)
+ {
+ return Regex.Replace(str, @"\^[0-9]", "");
+ }
}
}