Beispiel #1
0
        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"]);
                }
            }
        }
Beispiel #2
0
        /// <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();
        }
Beispiel #3
0
        /// <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();
            }
        }
Beispiel #4
0
        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();
                }
            }
        }
Beispiel #5
0
        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();
            }
        }
Beispiel #6
0
 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!!!");
 }
Beispiel #7
0
        /// <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;
                }
            }
        }
Beispiel #8
0
        /// <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();
        }
Beispiel #9
0
        /// <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;
                }
            }
        }
Beispiel #10
0
        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();
        }