public override void OnSecond() { using (StreamReader reader = new StreamReader(File.Open(GetWorkingDirectory() + "../Dedicated_SSNL_" + srv_rowServer["ID"] + ".log", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) { reader.BaseStream.Seek(srv_iLastLogLocation, SeekOrigin.Begin); while (!reader.EndOfStream) { string strLine = reader.ReadLine(); if (strLine.Length > 0) { if (strLine[0] == '<') { XMLTag tag = SimpleXMLReader.Parse(strLine); if (tag.Name == "server_running") { SSNL.Log(this, "Running."); } } } } if (srv_iLastLogLocation != reader.BaseStream.Position) { srv_iLastLogLocation = reader.BaseStream.Position; SSNL.DB.Query("UPDATE `servers` SET `_LogLocation`=" + srv_iLastLogLocation + " WHERE `ID`=" + srv_rowServer["ID"]); } } }
/// <summary> /// Stop the dedicated server process /// </summary> public override void StopServer() { srv_bClosing = true; try { srv_proc.Kill(); } catch { } srv_proc = null; SSNL.Log(this, "Server killed!"); SaveStats(); }
/// <summary> /// Creates a new server and immediately starts the dedicated server /// </summary> /// <param name="rowServer">MySQL data row for the server information</param> public SeriousEngine3(Dictionary <string, string> rowServer, Dictionary <string, string> rowGame) { srv_rowServer = rowServer; srv_rowGame = rowGame; srv_dicPlayers = new Dictionary <string, Player>(); for (int i = 0; i < srv_aPlayerIndices.Length; i++) { srv_aPlayerIndices[i] = ""; } // if the last used process ID is still valid Process proc = null; try { proc = Process.GetProcessById(int.Parse(rowServer["_PID"])); } catch { } if (proc != null && proc.ProcessName == srv_rowGame["Executable"].Replace(".exe", "")) { // take the existing process srv_bClosing = false; srv_proc = proc; srv_strRconPassword = rowServer["_Rcon"]; SSNL.Log(this, "Re-hooking"); // start rcon connection if (!srv_bRestarting) { new Thread(new ThreadStart(ConnectionThread)).Start(); new Thread(new ThreadStart(WaitThread)).Start(); } // save initial stats SaveStats(); } else { // otherwise, just start a new process StartServer(); } }
public void WaitThread() { while (true) { Thread.Sleep(1000); _ctSeconds++; if (_ctLastPlayers > 0) { dynamic resActions = SSNL.DB.Query("SELECT * FROM `adminactions` WHERE `Server`=" + srv_rowServer["ID"] + " AND `Handled`=0 ORDER BY `ID` DESC"); for (int i = 0; i < resActions.Length; i++) { dynamic action = resActions[i]; AdminAction(action["Type"], action["SteamID"]); SSNL.DB.Query("UPDATE `adminactions` SET `Handled`=1 WHERE `ID`=" + action["ID"]); } } _ctLastPlayers = srv_ctPlayers; OnSecond(); // if server closed unexpectedly if (!IsServerRunning() && srv_proc != null && !srv_bClosing) { SSNL.Log(this, "Server crashed"); // restart it srv_proc = null; srv_bRestarting = true; StartServer(); } // if a minute passed if (_ctSeconds % 60 == 0) { // save stats SaveStats(); } } }
public SeriousSamRevolution(Dictionary <string, string> rowServer, Dictionary <string, string> rowGame) { srv_rowServer = rowServer; srv_rowGame = rowGame; // if the last used process ID is still valid Process proc = null; try { proc = Process.GetProcessById(int.Parse(rowServer["_PID"])); } catch { } if (proc != null && proc.ProcessName == srv_rowGame["Executable"].Replace(".exe", "")) { // take the existing process srv_bClosing = false; srv_proc = proc; srv_strRconPassword = rowServer["_Rcon"]; srv_ctPlayers = int.Parse(rowServer["_Players"]); srv_iLastLogLocation = int.Parse(rowServer["_LogLocation"]); SSNL.Log(this, "Re-hooking"); // start rcon connection if (!srv_bRestarting) { new Thread(new ThreadStart(WaitThread)).Start(); } // save initial stats SaveStats(); } else { // otherwise, just start a new process StartServer(); } }
public override void AdminAction(string strType, string strSteamID) { SSNL.Log(this, "Attempted an admin action " + strType + " for Steam ID " + strSteamID + " on HD FE server, NOT IMPLEMENTED!!!"); }
/// <summary> /// Rcon thread connection /// </summary> public void ConnectionThread() { while (true) { TcpClient client = null; while (true) { try { client = new TcpClient(); client.Connect("127.0.0.1", GetPort()); break; } catch (Exception ex) { //SSNL.Log(this, "Failed to connect to rcon, retrying... (" + ex.Message + ")"); } } srv_reader = new StreamReader(client.GetStream(), Encoding.UTF8); srv_writer = new StreamWriter(client.GetStream(), Encoding.UTF8) { NewLine = "\r\n", AutoFlush = true }; try { RconSend(GetRconPassword()); SSNL.Log(this, "Rcon connected"); RconSend("prj_strDisabledVoteTypes=\"" + GetDisallowedVotes() + "\""); RconSend("prj_bExitOnSessionEnd=true"); } catch { } // we won't get information about current players - we don't care much about that... SSNL.DB.Query("DELETE FROM `activeplayers` WHERE `Server`=" + srv_rowServer["ID"]); SSNL.DB.Query("UPDATE `Servers` SET `_Players`=0 WHERE `ID`=" + srv_rowServer["ID"]); srv_ctPlayers = 0; while (true) { string strLine = ""; try { strLine = srv_reader.ReadLine(); } catch { SSNL.Log(this, "Lost connection"); break; } if (strLine == null) { SSNL.Log(this, "Line reading error"); break; } if (strLine.StartsWith("Server accepted connection from IP: ")) { string[] parse = strLine.Split(new string[] { ": ", ", ", "." }, StringSplitOptions.None); string strSteamID = parse[1]; int iPlayerIndex = int.Parse(parse[3]); if (IsPrivate()) { Whitelist whitelist = GetWhitelist(); if (!whitelist.IsPlayerWhitelisted(strSteamID)) { SSNL.Log(this, "Player with ID " + strSteamID + " is not allowed to play in this server - kicking!"); RconSend("Wait(Delay(4));samKickClient(" + iPlayerIndex + ");"); break; } } SSNL.Log(this, "Player with ID " + strSteamID + " is connecting"); } else if (strLine.StartsWith("<")) { XMLTag tag = SimpleXMLReader.Parse(strLine); string strPlayer = ""; if (tag.Attributes.ContainsKey("player")) { strPlayer = tag["player"]; } switch (tag.Name) { case "playerjoined": if (IsServerStrict()) { RconSend("chatSay(\"~ " + SSNL.LuaSafe(strPlayer) + ", this is a STRICT server. Please see: serioussam.nl/strict\")"); } SSNL.Log(this, strPlayer + " joined"); break; case "playerleft": SSNL.Log(this, strPlayer + " left"); break; case "chat": if (strPlayer == "") { // ignore messages from server break; } if (tag.Content.StartsWith("/")) { string[] strParse = tag.Content.Split(' '); switch (strParse[0]) { case "/stats": RconSend("chatSay(\"~ We don't track stats yet. :)\")"); break; } } SSNL.Log(this, HtmlDecode(strPlayer) + ": " + tag.Content); break; case "playerkilled": int iLastWarning = 2; string strWeapon = tag["damageinflictorweapon"]; string strKiller = tag["killerplayer"]; string strKillerId = tag["killerplayerid"]; if (strKiller == "") { SSNL.Log(this, HtmlDecode(strPlayer) + " died"); } else if (strKiller == strPlayer) { SSNL.Log(this, HtmlDecode(strPlayer) + " killed himself"); } else { SSNL.Log(this, HtmlDecode(strKiller) + " killed " + HtmlDecode(strPlayer)); } break; } } } // if the server was supposed to close if (srv_bClosing) { // don't attempt to reconnect break; } } }
/// <summary> /// Start the dedicated server process /// </summary> public override void StartServer() { srv_bClosing = false; if (srv_proc != null) { SSNL.Log(this, "Warning: Killing still-existing server process with ID " + srv_proc.Id); srv_proc.Kill(); srv_proc = null; } SSNL.Log(this, "Starting"); // generate rcon password srv_strRconPassword = ""; string strAllowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (int i = 0; i < 16; i++) { srv_strRconPassword += strAllowedCharacters[SSNL.Rnd.Next(0, strAllowedCharacters.Length)]; } // get server flags in advance string strServerFlags = GetServerFlags(); if (strServerFlags != "") { strServerFlags = " [" + strServerFlags + "]"; } // write config file string strConfigFilename = GetWorkingDirectory() + "..\\SSNL\\_Server_" + srv_rowServer["ID"] + ".lua"; if (File.Exists(strConfigFilename)) { File.Delete(strConfigFilename); } using (StreamWriter writer = new StreamWriter(File.Create(strConfigFilename))) { writer.WriteLine("prj_strMultiplayerSessionName = \"" + GetName() + strServerFlags + "\""); writer.WriteLine("gam_bAllowJoinInProgress = " + (srv_rowServer["Duel"] == "1" ? "0" : "1")); srv_strBans = ""; dynamic resBans = SSNL.DB.Query("SELECT * FROM `bans` WHERE `Server`=-1 OR `Server`=" + srv_rowServer["ID"]); // steamID;steamID;steamID#endingTimestamp;steamID#endingTimestamp foreach (dynamic ban in resBans) { string strBanListing = ban["SteamID"]; if (ban["Time"] != "0") { strBanListing += "#" + CalculateBanUTC(ban["BanTime"], ban["Time"]) + "#"; } srv_strBans += strBanListing + ";"; } writer.WriteLine("ser_strBanList = \"" + srv_strBans + "\""); //writer.WriteLine("dofile \"SSNL/Global.lua\""); } // build start arguments string strStartArguments = ""; strStartArguments += "+gamemode " + GetGameMode() + " "; //strStartArguments += "+sessionname \"" + GetName() + strServerFlags + "\" "; strStartArguments += "+exec \"" + strConfigFilename.Replace(GetWorkingDirectory() + "..\\", "") + "\" "; strStartArguments += "+maxplayers " + GetMaxPlayers() + " "; strStartArguments += "+port " + GetPort() + " "; strStartArguments += "+level " + GetFirstLevel() + " "; strStartArguments += "+maplistfile " + GetLevelListFile() + " "; strStartArguments += "+rconpass " + GetRconPassword() + " "; strStartArguments += "+fps 150 "; strStartArguments += "+gam_bAllowPowerupItems " + (GetPups() ? "1" : "0") + " "; strStartArguments += srv_rowServer["Extra"]; // start process srv_proc = Process.Start(new ProcessStartInfo() { WorkingDirectory = srv_rowGame["WorkingDirectory"], FileName = srv_rowGame["Executable"], Arguments = strStartArguments.Trim(), WindowStyle = ProcessWindowStyle.Hidden, }); // start rcon connection if (!srv_bRestarting) { new Thread(new ThreadStart(ConnectionThread)).Start(); new Thread(new ThreadStart(WaitThread)).Start(); } // save initial stats SaveStats(); }
/// <summary> /// Rcon thread connection /// </summary> public void ConnectionThread() { while (true) { TcpClient client = null; while (true) { try { client = new TcpClient(); client.Connect("127.0.0.1", GetPort()); break; } catch (Exception ex) { //SSNL.Log(this, "Failed to connect to rcon, retrying... (" + ex.Message + ")"); } } srv_reader = new StreamReader(client.GetStream(), Encoding.UTF8); srv_writer = new StreamWriter(client.GetStream(), Encoding.UTF8) { NewLine = "\r\n", AutoFlush = true }; try { RconSend(GetRconPassword()); SSNL.Log(this, "Rcon connected"); RconSend("prj_bExitOnSessionEnd=true"); RconSend("gam_bInfiniteAmmo=" + srv_rowServer["InfiniteAmmo"]); } catch { } // we won't get information about current players - we don't care much about that... SSNL.DB.Query("DELETE FROM `activeplayers` WHERE `Server`=" + srv_rowServer["ID"]); SSNL.DB.Query("UPDATE `Servers` SET `_Players`=0 WHERE `ID`=" + srv_rowServer["ID"]); srv_ctPlayers = 0; while (true) { string strLine = ""; try { strLine = srv_reader.ReadLine(); } catch { SSNL.Log(this, "Lost connection"); break; } if (strLine == null) { SSNL.Log(this, "Line reading error"); break; } if (strLine.StartsWith("Server accepted connection from IP: ")) { string[] parse = strLine.Split(new string[] { ": ", ", ", "." }, StringSplitOptions.None); string strSteamID = parse[1]; int iPlayerIndex = int.Parse(parse[3]); srv_aPlayerIndices[iPlayerIndex] = strSteamID; if (SSNL.DB.Query("SELECT * FROM `activeplayers` WHERE `Server`=" + srv_rowServer["ID"] + " AND `SteamID`='" + strSteamID + "'").Length == 0) { SSNL.DB.Query("INSERT INTO `activeplayers` (`Server`,`Spectating`,`SteamID`,`Name`,`Frags`,`Deaths`) VALUES(" + srv_rowServer["ID"] + ",1,'" + strSteamID + "','',0,0)"); } UpdatePlayerCount(); if (IsPrivate()) { Whitelist whitelist = GetWhitelist(); if (!whitelist.IsPlayerWhitelisted(strSteamID)) { SSNL.Log(this, "Player with ID " + strSteamID + " is not allowed to play in this server - kicking!"); RconSend("Wait(Delay(4));gamKickByIP(\"" + strSteamID + "\");"); break; } } SSNL.Log(this, "Player with ID " + strSteamID + " is connecting"); } else if ( strLine.StartsWith("Server received a disconnect message from ") || strLine.StartsWith("Server sent a disconnect message to ") || strLine.StartsWith("Server terminating client ")) { int iPlayerIndex = int.Parse(strLine.Split(new string[] { "from ", "to ", "client ", "." }, StringSplitOptions.None)[1]); SSNL.DB.Query("DELETE FROM `activeplayers` WHERE `SteamID`='" + srv_aPlayerIndices[iPlayerIndex] + "'"); srv_aPlayerIndices[iPlayerIndex] = ""; UpdatePlayerCount(); } else if (strLine.StartsWith("<")) { XMLTag tag = SimpleXMLReader.Parse(strLine); string strPlayer = ""; string strPlayerId = ""; int iAdmin = 0; if (tag.Attributes.ContainsKey("player")) { strPlayer = tag["player"]; } if (tag.Attributes.ContainsKey("playerid")) { strPlayerId = tag["playerid"]; } switch (tag.Name) { case "playerjoined": if (!srv_dicPlayers.ContainsKey(strPlayerId)) { srv_dicPlayers[strPlayerId] = new Player(); } else { srv_dicPlayers[strPlayerId].ResetStats(); } srv_dicPlayers[strPlayerId].ply_strName = strPlayer; SSNL.DB.Query("UPDATE `activeplayers` SET `Spectating`=0,`Name`='" + SSNL.DB.Safe(strPlayer) + "' WHERE `SteamID`='" + strPlayerId + "'"); if (IsServerStrict()) { RconSend("chatSay(\"~ " + SSNL.LuaSafe(strPlayer) + ", this is a STRICT server. Please see: serioussam.nl/strict\")"); } SSNL.Log(this, strPlayer + " joined"); break; case "playerleft": if (srv_dicPlayers.ContainsKey(strPlayerId)) { srv_dicPlayers.Remove(strPlayerId); } SSNL.Log(this, strPlayer + " left"); break; case "roundstart": srv_strCurrentGameMode = tag["gamemode"]; srv_iCurrentFragLimit = int.Parse(tag["fraglimit"]); srv_iCurrentTimeLimit = int.Parse(tag["timelimit"]); srv_iCurrentGoalsLimit = int.Parse(tag["goalslimit"]); srv_iCurrentMinPlayers = int.Parse(tag["minplayers"]); srv_iCurrentMaxPlayers = int.Parse(tag["maxplayers"]); srv_bCurrentJoinInProgress = tag["joininprogress"] == "1"; SSNL.DB.Query("UPDATE `activeplayers` SET `Spectating`=1,`Frags`=0,`Deaths`=0 WHERE `Server`=" + srv_rowServer["ID"]); SSNL.Log(this, "Round starting"); break; case "chat": if (strPlayer == "" || strPlayerId == "[admin]") { // ignore messages from server break; } if (tag.Content.StartsWith("/")) { iAdmin = SSNL.IsPlayerAdmin(strPlayerId); string[] strParse = tag.Content.Split(' '); switch (strParse[0]) { case "/stats": RconSend("chatSay(\"~ We don't track stats yet. :)\")"); break; } } SSNL.DB.Query("UPDATE `activeplayers` SET `Name`='" + SSNL.DB.Safe(strPlayer) + "' WHERE `SteamID`='" + strPlayerId + "'"); // if player is using chatSay("\n"), kick! *giggles* if (tag.Content.Contains("\n")) { RconSend("gamKickByIP(\"" + strPlayerId + "\")"); } SSNL.Log(this, HtmlDecode(strPlayer) + ": " + tag.Content); break; case "playerkilled": int iLastWarning = 2; string strWeapon = tag["damageinflictorweapon"]; string strKiller = tag["killerplayer"]; string strKillerId = tag["killerplayerid"]; if (strKiller == "") { SSNL.Log(this, HtmlDecode(strPlayer) + " died"); } else if (strKiller == strPlayer) { SSNL.Log(this, HtmlDecode(strPlayer) + " killed himself"); } else { SSNL.Log(this, HtmlDecode(strKiller) + " killed " + HtmlDecode(strPlayer)); } if (srv_dicPlayers.ContainsKey(strPlayerId)) { srv_dicPlayers[strPlayerId].ply_iDeaths++; SSNL.DB.Query("UPDATE `activeplayers` SET `Deaths`=`Deaths`+1 WHERE `SteamID`='" + strPlayerId + "'"); } if (strKillerId != "") { if (srv_dicPlayers.ContainsKey(strKillerId)) { srv_dicPlayers[strKillerId].ply_iKills++; SSNL.DB.Query("UPDATE `activeplayers` SET `Frags`=`Frags`+1 WHERE `SteamID`='" + strKillerId + "'"); } } // if strict server if (IsServerStrict()) { // disallowing of certain weapons if (srv_strCurrentGameMode != "InstantKill") { string[] strDisallowedWeapons = { "Cannon", "Sniper", "Chainsaw" }; // if disallowed weapon used if (strDisallowedWeapons.Contains(strWeapon)) { // if this player already received the max amount of warnings about disallowed weapons if (srv_dicPlayers.ContainsKey(strKillerId)) { if (srv_dicPlayers[strKillerId].ply_iWarnings == iLastWarning) { SSNL.Log("Player " + strKiller + " (" + strKillerId + ") got kicked for disallowed weapon usage: " + strWeapon); RconSend("chatSay(\"~ Kicking " + SSNL.LuaSafe(strKiller) + " for disallowed weapon usage.\")"); RconSend("gamKickByIP(\"" + strKillerId + "\")"); } else { SSNL.Log("Player " + strKiller + " (" + strKillerId + ") got a warning for disallowed weapon usage: " + strWeapon); srv_dicPlayers[strKillerId].ply_iWarnings++; RconSend("chatSay(\"~ " + (srv_dicPlayers[strKillerId].ply_iWarnings == iLastWarning ? "FINAL WARNING" : "WARNING") + ": " + SSNL.LuaSafe(strKiller) + ", " + strWeapon + " is NOT ALLOWED!!\")"); } } } } } break; } } } // if the server was supposed to close if (srv_bClosing) { // don't attempt to reconnect break; } } }
public override void StartServer() { srv_bClosing = false; if (srv_proc != null) { SSNL.Log(this, "Warning: Killing still-existing server process with ID " + srv_proc.Id); srv_proc.Kill(); srv_proc = null; } SSNL.Log(this, "Starting"); SSNL.DB.Query("UPDATE `servers` SET `_LogLocation`=0 WHERE `ID`=" + srv_rowServer["ID"]); srv_iLastLogLocation = 0; // generate rcon password srv_strRconPassword = ""; string strAllowedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; for (int i = 0; i < 16; i++) { srv_strRconPassword += strAllowedCharacters[SSNL.Rnd.Next(0, strAllowedCharacters.Length)]; } // create dedicated scripts directory string strDirectory = GetWorkingDirectory() + "../Scripts/Dedicated/SSNL_" + srv_rowServer["ID"]; if (!Directory.Exists(strDirectory)) { Directory.CreateDirectory(strDirectory); } // init.ini if (File.Exists(strDirectory + "/init.ini")) { File.Delete(strDirectory + "/init.ini"); } using (StreamWriter writer = new StreamWriter(File.Create(strDirectory + "/init.ini"))) { writer.WriteLine("gam_strSessionName = \"" + GetName() + "\";"); writer.WriteLine("net_iPort = " + GetPort() + ";"); writer.WriteLine("gam_iStartMode = " + GetStartMode() + ";"); writer.WriteLine("gam_iStartDifficulty = 1;"); // normal diff only for now :I writer.WriteLine("gam_ctMaxPlayers = " + GetMaxPlayers() + ";"); writer.WriteLine("net_strAdminPassword = \"" + srv_strRconPassword + "\";"); writer.WriteLine("gam_bWaitAllPlayers = 0;"); writer.WriteLine("gam_iCredits = 0;"); writer.WriteLine("gam_bWeaponsStay = 0;"); writer.WriteLine("gam_iTimeLimit = 15;"); writer.WriteLine("gam_iFragLimit = 20;"); writer.WriteLine("ded_tmTimeout = 5;"); writer.WriteLine("ser_bWaitFirstPlayer = 1;"); /*string strBans = ""; * * writer.WriteLine("ser_strBanList = \"" + strBans + "\""); * writer.WriteLine("dofile \"SSNL/Global.lua\"");*/ } // 1_begin.ini if (File.Exists(strDirectory + "/1_begin.ini")) { File.Delete(strDirectory + "/1_begin.ini"); } using (StreamWriter writer = new StreamWriter(File.Create(strDirectory + "/1_begin.ini"))) { writer.WriteLine("ded_strLevel = \"" + GetFirstLevel() + "\";"); } // 1_end.ini if (File.Exists(strDirectory + "/1_end.ini")) { File.Delete(strDirectory + "/1_end.ini"); } using (StreamWriter writer = new StreamWriter(File.Create(strDirectory + "/1_end.ini"))) { writer.WriteLine("Say(\"Level finished.\");"); } // start process srv_proc = Process.Start(new ProcessStartInfo() { WorkingDirectory = srv_rowGame["WorkingDirectory"], FileName = srv_rowGame["Executable"], Arguments = "SSNL_" + srv_rowServer["ID"], WindowStyle = ProcessWindowStyle.Hidden, }); // start rcon connection if (!srv_bRestarting) { new Thread(new ThreadStart(WaitThread)).Start(); } // save initial stats SaveStats(); }