public override void HandleRequest()
        {
            int Pid = 0;
            int Unlock = 0;
            List<Dictionary<string, object>> Rows;

            // Setup Params
            if (Request.QueryString.ContainsKey("pid"))
                Int32.TryParse(Request.QueryString["pid"], out Pid);
            if (Request.QueryString.ContainsKey("id"))
                Int32.TryParse(Request.QueryString["id"], out Unlock);

            // Make sure we have valid parameters
            if (Pid == 0 || Unlock == 0)
            {
                Response.WriteResponseStart(false);
                Response.WriteHeaderLine("asof", "err");
                Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Invalid Syntax!");
                Response.Send();
                return;
            }

            // NOTE: The HttpServer will handle the DbConnectException
            using (Database = new StatsDatabase())
            {
                // Fetch Player
                Rows = Database.Query("SELECT availunlocks, usedunlocks FROM player WHERE id=@P0", Pid);
                if (Rows.Count == 0)
                {
                    Response.WriteResponseStart(false);
                    Response.WriteHeaderLine("asof", "err");
                    Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Player Doesnt Exist");
                    Response.Send();
                    return;
                }

                // Update Unlock, setting its state to 's' (unlocked)
                Database.Execute("UPDATE unlocks SET state = 's' WHERE id = @P0 AND kit = @P1", Pid, Unlock);

                // Update players used and avail unlock counts
                Database.Execute("UPDATE player SET availunlocks = @P0, usedunlocks = @P1 WHERE id = @P2",
                    int.Parse(Rows[0]["availunlocks"].ToString()) - 1,
                    int.Parse(Rows[0]["usedunlocks"].ToString()) + 1,
                    Pid
                );

                // Send Response
                Response.WriteResponseStart();
                Response.WriteHeaderLine("response");
                Response.WriteDataLine("OK");
                Response.Send();
            }
        }
        public override void HandleRequest()
        {
            // NOTE: The HttpServer will handle the DbConnectException
            using (Database = new StatsDatabase())
            {
                int Pid = 0;
                List<Dictionary<string, object>> Rows;

                // Setup Params
                if (Client.Request.QueryString.ContainsKey("pid"))
                    Int32.TryParse(Client.Request.QueryString["pid"], out Pid);

                // Fetch Player
                Rows = Database.Query("SELECT rank FROM player WHERE id=@P0", Pid);
                if (Rows.Count == 0)
                {
                    Response.WriteResponseStart(false);
                    Response.WriteFreeformLine("Player Doesnt Exist!");
                    Client.Response.Send();
                    return;
                }

                // Reset
                Database.Execute("UPDATE player SET chng=0, decr=0 WHERE id=@P0", Pid);
                Response.WriteResponseStart();
                Response.WriteFreeformLine(String.Format("Cleared rank notification {0}", Pid));
                Response.Send();
            }
        }
Esempio n. 3
0
        /// <summary>
        /// This request provides details on a particular players rank, and
        /// whether or not to show the user a promotion/demotion announcement
        /// </summary>
        /// <queryParam name="pid" type="int">The unique player ID</queryParam>
        /// <param name="Client">The HttpClient who made the request</param>
        /// <param name="Driver">The Stats Database Driver. Connection errors are handled in the calling object</param>
        public GetRankInfo(HttpClient Client, StatsDatabase Driver)
        {
            int Pid = 0;
            List<Dictionary<string, object>> Rows;

            // Setup Params
            if (Client.Request.QueryString.ContainsKey("pid"))
                Int32.TryParse(Client.Request.QueryString["pid"], out Pid);

            // Fetch Player
            Rows = Driver.Query("SELECT rank, chng, decr FROM player WHERE id=@P0", Pid);
            if (Rows.Count == 0)
            {
                Client.Response.WriteResponseStart(false);
                Client.Response.WriteHeaderLine("asof", "err");
                Client.Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Player Doesnt Exist");
                Client.Response.Send();
                return;
            }

            // Output status... chng set to 1 shows the Promotion Announcement, whereas decr shows the Demotion Announcement
            Client.Response.WriteResponseStart();
            Client.Response.WriteHeaderLine("rank", "chng", "decr");
            Client.Response.WriteDataLine(Rows[0]["rank"], Rows[0]["chng"], Rows[0]["decr"]);
            Client.Response.Send();

            // Reset
            Driver.Execute("UPDATE player SET chng=0, decr=0 WHERE id=@P0", Pid);
        }
Esempio n. 4
0
        public override void HandleRequest()
        {
            // NOTE: The HttpServer will handle the DbConnectException
            using (Database = new StatsDatabase())
            {
                int Pid = 0;

                // Setup Params
                if (Client.Request.QueryString.ContainsKey("pid"))
                    Int32.TryParse(Client.Request.QueryString["pid"], out Pid);

                // Fetch Player
                var Rows = Database.Query("SELECT rank, chng, decr FROM player WHERE id=@P0", Pid);
                if (Rows.Count == 0)
                {
                    Response.WriteResponseStart(false);
                    Response.WriteHeaderLine("asof", "err");
                    Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Player Doesnt Exist");
                    Response.Send();
                    return;
                }

                // Output status... chng set to 1 shows the Promotion Announcement, whereas decr shows the Demotion Announcement
                Response.WriteResponseStart();
                Response.WriteHeaderLine("rank", "chng", "decr");
                Response.WriteDataLine(Rows[0]["rank"], Rows[0]["chng"], Rows[0]["decr"]);
                Response.Send();

                // Reset
                Database.Execute("UPDATE player SET chng=0, decr=0 WHERE id=@P0", Pid);
            }
        }
        /// <summary>
        /// This request clears all rank announcements for a specific player
        /// </summary>
        /// <queryParam name="pid" type="int">The unique player ID</queryParam>
        /// <param name="Client">The HttpClient who made the request</param>
        /// <param name="Driver">The Stats Database Driver. Connection errors are handled in the calling object</param>
        public RankNotification(HttpClient Client, StatsDatabase Driver)
        {
            int Pid = 0;
            List<Dictionary<string, object>> Rows;

            // Setup Params
            if (Client.Request.QueryString.ContainsKey("pid"))
                Int32.TryParse(Client.Request.QueryString["pid"], out Pid);

            // Fetch Player
            Rows = Driver.Query("SELECT rank FROM player WHERE id=@P0", Pid);
            if (Rows.Count == 0)
            {
                Client.Response.WriteResponseStart(false);
                Client.Response.WriteFreeformLine("Player Doesnt Exist!");
                Client.Response.Send();
                return;
            }

            // Reset
            Driver.Execute("UPDATE player SET chng=0, decr=0 WHERE id=@P0", Pid);
            Client.Response.WriteResponseStart();
            Client.Response.WriteFreeformLine(String.Format("Cleared rank notification {0}", Pid));
            Client.Response.Send();
        }
        public override void HandleRequest()
        {
            int Pid;

            // make sure we have a valid player ID
            if (!Request.QueryString.ContainsKey("pid")
                || !Int32.TryParse(Request.QueryString["pid"], out Pid)
                || !Request.QueryString.ContainsKey("nick"))
            {
                Response.WriteResponseStart(false);
                Response.WriteHeaderLine("asof", "err");
                Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Invalid Syntax!");
                Response.Send();
                return;
            }

            // NOTE: The HttpServer will handle the DbConnectException
            using (Database = new StatsDatabase())
            {
                // Fetch Player
                string PlayerNick = Request.QueryString["nick"].Replace("%20", " ");
                string CC = (Request.QueryString.ContainsKey("cid")) ? Client.Request.QueryString["cid"] : "";
                if (Database.ExecuteScalar<int>("SELECT COUNT(*) FROM player WHERE id=@P0 OR name=@P1", Pid, PlayerNick) > 0)
                {
                    Response.WriteResponseStart(false);
                    Response.WriteFreeformLine("Player already Exists!");
                    Response.Send();
                    return;
                }

                // Create Player
                Database.Execute(
                    "INSERT INTO player(id, name, country, joined, isbot) VALUES(@P0, @P1, @P2, @P3, 0)",
                    Pid, PlayerNick, CC, DateTime.UtcNow.ToUnixTimestamp()
                );

                // Confirm
                Response.WriteResponseStart();
                Response.WriteFreeformLine("Player Created Successfully!");
                Response.Send();
            }
        }
Esempio n. 7
0
        /// <summary>
        /// This request creates a player with the specified Pid when called
        /// </summary>
        /// <queryParam name="pid" type="int">The unique player ID</queryParam>
        /// <queryParam name ="nick" type="string">Unique player nickname</queryParam>
        /// <param name="Client">The HttpClient who made the request</param>
        /// <param name="Driver">The Stats Database Driver. Connection errors are handled in the calling object</param>
        public CreatePlayer(HttpClient Client, StatsDatabase Driver)
        {
            int Pid;

            // make sure we have a valid player ID
            if (!Client.Request.QueryString.ContainsKey("pid")
                || !Int32.TryParse(Client.Request.QueryString["pid"], out Pid)
                || !Client.Request.QueryString.ContainsKey("nick"))
            {
                Client.Response.WriteResponseStart(false);
                Client.Response.WriteHeaderLine("asof", "err");
                Client.Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Invalid Syntax!");
                Client.Response.Send();
                return;
            }

            // Fetch Player
            string PlayerNick = Client.Request.QueryString["nick"].Replace("%20", " ");
            string CC = (Client.Request.QueryString.ContainsKey("cid")) ? Client.Request.QueryString["cid"] : "";
            var Rows = Driver.Query("SELECT name FROM player WHERE id=@P0 OR name=@P1", Pid, PlayerNick);
            if (Rows.Count > 0)
            {
                Client.Response.WriteResponseStart(false);
                Client.Response.WriteFreeformLine("Player already Exists!");
                Client.Response.Send();
                return;
            }

            // Create Player
            Driver.Execute(
                "INSERT INTO player(id, name, country, joined, isbot) VALUES(@P0, @P1, @P2, @P3, 0)",
                Pid, PlayerNick, CC, DateTime.UtcNow.ToUnixTimestamp()
            );

            // Confirm
            Client.Response.WriteResponseStart();
            Client.Response.WriteFreeformLine("Player Created Successfully!");
            Client.Response.Send();
        }
        /// <summary>
        /// Reset stats button click event
        /// </summary>
        private async void ResetStatsBtn_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure you want to reset players stats?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                try
                {
                    TaskForm.Show(this, "Reset Player Stats", "Reseting Player \"" + Player["name"] + "\"'s Stats", false);
                    await Task.Run(() =>
                    {
                        // Delete the players
                        using (StatsDatabase Driver = new StatsDatabase())
                        {
                            // Delete old player statistics
                            Driver.DeletePlayer(Pid, TaskForm.Progress);

                            // Insert a new player record
                            Driver.Execute(
                                "INSERT INTO player(id, name, country, joined, clantag, permban, isbot) VALUES(@P0, @P1, @P2, @P3, @P4, @P5, @P6)",
                                Pid, Player["name"], Player["country"], Player["joined"], Player["clantag"], Player["permban"], Player["isbot"]
                            );
                        }
                    });

                    // Reload player
                    LoadPlayer();
                    Notify.Show("Player Stats Reset Successfully!", "Operation Successful", AlertType.Success);
                }
                catch (DbConnectException Ex)
                {
                    HttpServer.Stop();
                    ExceptionForm.ShowDbConnectError(Ex);
                    TaskForm.CloseForm();
                    this.Close();
                    return;
                }
                catch (Exception E)
                {
                    // Show exception error
                    using (ExceptionForm Form = new ExceptionForm(E, false))
                    {
                        Form.Message = String.Format("Failed to reset player stats!{1}{1}Error: {0}", E.Message, Environment.NewLine);
                        Form.ShowDialog();
                    }
                }
                finally
                {
                    // Close task form
                    TaskForm.CloseForm();
                }
            }
        }
        /// <summary>
        /// Reset Unlocks Button Click Event
        /// </summary>
        private void ResetUnlocksBtn_Click(object sender, EventArgs e)
        {
            try
            {
                // Create New Player Unlock Data
                StringBuilder Query = new StringBuilder("INSERT INTO unlocks VALUES ");

                // Normal unlocks
                for (int i = 11; i < 100; i += 11)
                    Query.AppendFormat("({0}, {1}, 'n'), ", Pid, i);

                // Sf Unlocks
                for (int i = 111; i < 556; i += 111)
                {
                    Query.AppendFormat("({0}, {1}, 'n')", Pid, i);
                    if (i != 555) 
                        Query.Append(", ");
                }

                // Do driver queries
                using (StatsDatabase Driver = new StatsDatabase())
                using (DbTransaction T = Driver.BeginTransaction())
                {
                    try
                    {
                        // Perform queries
                        Driver.Execute("DELETE FROM unlocks WHERE id = " + Pid);
                        Driver.Execute("UPDATE player SET usedunlocks = 0 WHERE id = " + Pid);
                        Driver.Execute(Query.ToString());
                        T.Commit();

                        // Notify user
                        Notify.Show("Player Unlocks Have Been Reset", "This player will be able to select his new unlocks upon logging in.", AlertType.Success);
                    }
                    catch
                    {
                        T.Rollback();
                        throw;
                    }
                }
            }
            catch (DbConnectException Ex)
            {
                HttpServer.Stop();
                ExceptionForm.ShowDbConnectError(Ex);
                this.Close();
            }
        }
Esempio n. 10
0
        /// <summary>
        /// Start the ASP listener, and Connects to the stats database
        /// </summary>
        public static void Start()
        {
            // Can't start if we are already running!
            if (IsRunning) return;

            // === Try to connect to the database
            using (StatsDatabase Database = new StatsDatabase())  
            {
                if (!Database.TablesExist)
                {
                    string message = "In order to use the Private Stats feature of this program, we need to setup a database. "
                        + "You may choose to do this later by clicking \"Cancel\". Would you like to setup the database now?";
                    DialogResult R = MessageBox.Show(message, "Stats Database Setup", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    if (R == DialogResult.Yes)
                        SetupManager.ShowDatabaseSetupForm(DatabaseMode.Stats, MainForm.Instance);

                    // Call the stopped event to Re-enable the main form's buttons
                    Stopped(null, EventArgs.Empty);
                    return;
                }

                // Initialize the stats manager
                StatsManager.Load(Database);

                // Drop the SQLite ip2nation country tables (old table versions)
                if (Database.DatabaseEngine == DatabaseEngine.Sqlite)
                {
                    string query = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='ip2nation'";
                    if (Database.ExecuteScalar<bool>(query)) // 0 count converts to false
                    {
                        Database.Execute("DROP TABLE IF EXISTS 'ip2nation';");
                        Database.Execute("DROP TABLE IF EXISTS 'ip2nationcountries';");
                        Database.Execute("VACUUM;");
                    }
                }
            }

            // === Compile our templates
            string path = Path.Combine(Program.RootPath, "Web", "Bf2Stats", "Views");
            foreach (string file in Directory.EnumerateFiles(path, "*.cshtml"))
            {
                // If this template file is loaded already, then skip
                string fileName = Path.GetFileName(file);
                if (Engine.Razor.IsTemplateCached(fileName, ModelType))
                    continue;

                // Open the file, and compile it
                try
                {
                    using (FileStream stream = File.OpenRead(file))
                    using (StreamReader reader = new StreamReader(stream))
                        Engine.Razor.Compile(reader.ReadToEnd(), fileName, ModelType);
                }
                catch (TemplateCompilationException e)
                {
                    // Show the Exception form so the user can view
                    DialogResult Res = ExceptionForm.ShowTemplateError(e, file);

                    // If the user clicked "Quit", we stop
                    if (Res == DialogResult.Abort) return;
                }
            }
            

            // === Load XML stats and awards files
            Bf2StatsData.Load();
            BackendAwardData.BuildAwardData();

            // Start the Listener and accept new connections
            try
            {
                Listener.Start();
                Listener.BeginGetContext(HandleRequest, Listener);
            }
            catch (ObjectDisposedException)
            {
                // If we are disposed (happens when port 80 was in use already before, and we tried to start)
                // Then we need to start over with a new Listener
                CreateHttpListener();
                Listener.Start();
                Listener.BeginGetContext(HandleRequest, Listener);
            }
                
            // Fire Startup Event
            Started(null, EventArgs.Empty);
        }
Esempio n. 11
0
        /// <summary>
        /// This request provides details on a particular players rank, and
        /// whether or not to show the user a promotion/demotion announcement
        /// </summary>
        /// <queryParam name="nick" type="string">The unique player's Name</queryParam>
        /// <queryParam name="ai" type="int">Defines whether the player is a bot (used by bf2server)</queryParam>
        /// <queryParam name="playerlist" type="int">Defines whether to list the players who's nick is similair to the Nick param</queryParam>
        /// <param name="Client">The HttpClient who made the request</param>
        /// <param name="Driver">The Stats Database Driver. Connection errors are handled in the calling object</param>
        public GetPlayerID(HttpClient Client, StatsDatabase Driver)
        {
            // Setup Variables
            List<Dictionary<string, object>> Rows;
            Dictionary<string, string> QueryString = Client.Request.QueryString;

            // Querystring vars
            int IsAI = 0;
            int ListPlayers = 0;
            string PlayerNick = "";

            // Setup Params
            if (QueryString.ContainsKey("nick"))
                PlayerNick = QueryString["nick"].Replace("%20", " ");
            if (QueryString.ContainsKey("ai"))
                Int32.TryParse(QueryString["ai"], out IsAI);
            if (QueryString.ContainsKey("playerlist"))
                Int32.TryParse(QueryString["playerlist"], out ListPlayers);

            // Handle Request
            if (!String.IsNullOrWhiteSpace(PlayerNick))
            {
                int Pid;

                // Create player if they donot exist
                Rows = Driver.Query("SELECT id FROM player WHERE name = @P0 LIMIT 1", PlayerNick);
                if (Rows.Count == 0)
                {
                    // Grab new Player ID
                    Pid = LowestPid--;

                    // Create New Player Unlock Data
                    StringBuilder Query = new StringBuilder("INSERT INTO unlocks VALUES ");

                    // Normal unlocks
                    for (int i = 11; i < 100; i += 11)
                        Query.AppendFormat("({0}, {1}, 'n'), ", Pid, i);

                    // Sf Unlocks
                    for (int i = 111; i < 556; i += 111)
                    {
                        Query.AppendFormat("({0}, {1}, 'n')", Pid, i);
                        if (i != 555)
                            Query.Append(", ");
                    }

                    // Create Player
                    Driver.Execute(
                        "INSERT INTO player(id, name, joined, isbot) VALUES(@P0, @P1, @P2, @P3)",
                        Pid, PlayerNick, DateTime.UtcNow.ToUnixTimestamp(), IsAI
                    );

                    // Create player unlocks
                    Driver.Execute(Query.ToString());
                }
                else
                    Pid = Int32.Parse(Rows[0]["id"].ToString());

                // Send Response
                Client.Response.WriteResponseStart();
                Client.Response.WriteHeaderLine("pid");
                Client.Response.WriteDataLine(Pid);
            }
            else if (ListPlayers != 0)
            {
                // Prepare Response
                Client.Response.WriteResponseStart();
                Client.Response.WriteHeaderLine("pid");

                // Fetch Players
                Rows = Driver.Query("SELECT id FROM player WHERE ip <> '127.0.0.1'");
                foreach (Dictionary<string, object> Player in Rows)
                    Client.Response.WriteDataLine(Player["id"]);
            }
            else
            {
                Client.Response.WriteResponseStart(false);
                Client.Response.WriteHeaderLine("asof", "err");
                Client.Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Invalid Syntax!");
            }

            // Send Response
            Client.Response.Send();
        }
Esempio n. 12
0
        /// <summary>
        /// Initializes a new Snapshot, with the specified Date it was Posted
        /// </summary>
        /// <param name="Snapshot">The snapshot source</param>
        /// <param name="Date">The original date in which this snapshot was created</param>
        public Snapshot(string Snapshot, DateTime Date, StatsDatabase Database)
        {
            // Load out database connection
            this.Driver = Database;
            this.Date = Date;
            this.TimeStamp = Date.ToUnixTimestamp();

            // Get our snapshot key value pairs
            string[] Data = Snapshot.Split('\\');
            Snapshot = null;

            // Check for invalid snapshot string. All snapshots have at least 36 data pairs,
            // and has an Even number of data sectors. We must also have an "End of File" Sector
            if (Data.Length < 36 || Data.Length % 2 != 0 || !Data.Contains("EOF"))
            {
                IsValid = false;
                return;
            }

            // Define if we are central update. the "cdb_update" variable must be the LAST sector in snapshot
            this.IsCentralUpdate = (Data[Data.Length - 2] == "cdb_update" && Data[Data.Length - 1] == "1");

            // Server data
            this.ServerPrefix = Data[0];
            this.ServerName = Data[1];
            this.ServerPort = int.Parse(Data[3].ToString());
            this.QueryPort = int.Parse(Data[5].ToString());

            // Map Data
            this.MapName = Data[7];
            this.MapId = int.Parse(Data[9]);
            this.MapStart = (int)Convert.ToDouble(Data[11], CultureInfo.InvariantCulture.NumberFormat);
            this.MapEnd = (int)Convert.ToDouble(Data[13], CultureInfo.InvariantCulture.NumberFormat);

            // Misc Data
            this.WinningTeam = int.Parse(Data[15]);
            this.GameMode = int.Parse(Data[17]);
            this.Mod = Data[21];
            this.PlayersConnected = int.Parse(Data[23]);

            // Army Data
            this.WinningArmy = int.Parse(Data[25]);
            this.Team1Army = int.Parse(Data[27]);
            this.Team1Tickets = int.Parse(Data[29]);
            this.Team2Army = int.Parse(Data[31]);
            this.Team2Tickets = int.Parse(Data[33]);

            // Setup snapshot variables
            PlayerData = new Dictionary<int, Dictionary<string, string>>();
            KillData = new Dictionary<int, Dictionary<string, string>>();

            // Check for custom map, with no ID
            if (MapId == 99)
            {
                IsCustomMap = true;

                // Check for existing map data
                List<Dictionary<string, object>> Rows = Driver.Query("SELECT id FROM mapinfo WHERE name=@P0", MapName);
                if (Rows.Count == 0)
                {
                    // Create new MapId. Id's 700 - 1000 are reserved for unknown maps in the Constants.py file
                    // There should never be more then 300 unknown map id's, considering 1001 is the start of KNOWN
                    // Custom mod map id's
                    Rows = Driver.Query("SELECT COALESCE(MAX(id), 699) AS id FROM mapinfo WHERE id BETWEEN 700 AND 1000");
                    MapId = Int32.Parse(Rows[0]["id"].ToString()) + 1;

                    // Insert map data, so we dont lose this mapid we generated
                    Driver.Execute("INSERT INTO mapinfo(id, name) VALUES (@P0, @P1)", MapId, MapName);
                }
                else
                    MapId = Int32.Parse(Rows[0]["id"].ToString());
            }
            else
                IsCustomMap = (MapId >= 700);

            // Do player snapshots, sector 36 is first player
            for (int i = 36; i < Data.Length; i += 2)
            {
                // Format: "DataKey_PlayerId". PlayerId is not the PID, but rather
                // the player INDEX
                string[] Parts = Data[i].Split('_');

                // Ignore uncomplete snapshots
                if (Parts.Length == 1)
                {
                    // Unless we are at the end of file, IF there is no PID
                    // Given for an item, the snapshot is invalid!
                    if (Parts[0] == "EOF")
                        break;
                    else
                        IsValid = false;
                    return;
                }

                // If the item key is "pID", then we have a new player record
                int id = int.Parse(Parts[1]);
                if (Parts[0] == "pID")
                {
                    PlayerData.Add(id, new Dictionary<string, string>());
                    KillData.Add(id, new Dictionary<string, string>());
                }

                // Kill and death data has its own array key
                if (Parts[0] == "mvks")
                    continue;

                if (Parts[0] == "mvns")
                    KillData[id].Add(Data[i + 1], Data[i + 3]);
                else
                    PlayerData[id].Add(Parts[0], Data[i + 1]);
            }

            // Set that we appear to be valid
            IsValid = true;
        }
Esempio n. 13
0
        /// <summary>
        /// Checks the rank tenure, and assigns a new General
        /// </summary>
        private void GenCheck(StatsDatabase Driver)
        {
            Log("Processing GENERAL Rank", LogLevel.Notice);

            // Vars
            List<Dictionary<string, object>> Rows;
            List<Dictionary<string, object>> Players;

            // Fetch all Sergeant Major's, Order by Score
            Players = Driver.Query("SELECT id, score FROM player WHERE rank=20 OR rank=21 ORDER BY score DESC LIMIT 1");
            if (Players.Count == 1)
            {
                int Id = Int32.Parse(Players[0]["id"].ToString());

                // Check for currently awarded Smoc
                Rows = Driver.Query("SELECT id, earned FROM awards WHERE awd=6666667 LIMIT 1");
                if (Rows.Count > 0)
                {
                    // Check for same and determine if minimum tenure servred
                    int MinTenure = Program.Config.ASP_SpecialRankTenure * 86400;
                    int Sid = Int32.Parse(Rows[0]["id"].ToString());
                    int Earned = Int32.Parse(Rows[0]["earned"].ToString());

                    // Assign new Smoc If the old SMOC's tenure is up, and the current SMOC is not the highest scoring SGM
                    if (Id != Sid && (Earned + MinTenure) < this.RoundEndTime)
                    {
                        // Delete the GENERAL award
                        Driver.Execute("DELETE FROM awards WHERE id=@P0 AND awd=6666667", Sid);

                        // Change current GENERAL rank back to 3 Star Gen
                        Driver.Execute("UPDATE player SET rank=20, chng=0, decr=1 WHERE id =" + Sid);

                        // Award new GENERAL award
                        Driver.Execute("INSERT INTO awards(id,awd,earned) VALUES(@P0,@P1,@P2)", Id, 6666667, this.RoundEndTime);

                        // Update new GENERAL's rank
                        Driver.Execute("UPDATE player SET rank=21, chng=1, decr=0 WHERE id =" + Id);
                    }
                }
                else
                {
                    // Award GENERAL award
                    Driver.Execute("INSERT INTO awards(id,awd,earned) VALUES(@P0,@P1,@P2)", Id, 6666667, this.RoundEndTime);

                    // Update GENERAL rank
                    Driver.Execute("UPDATE player SET rank=21, chng=1, decr=0 WHERE id =" + Id);
                }
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Initializes a new Snapshot, with the specified Date it was Posted
        /// </summary>
        /// <param name="Snapshot">The snapshot source</param>
        public Snapshot(string Snapshot, IPAddress ServerIp = null)
        {
            // Set some internal variables
            this.ServerIp = ServerIp ?? IPAddress.Loopback;
            this.Players = new List<Player>();
            this.DataString = Snapshot.Trim();
            string[] Data = DataString.Split('\\');
            Snapshot = null;

            // Check for invalid snapshot string. All snapshots have at least 36 data pairs,
            // and has an Even number of data sectors.
            if (Data.Length < 36 || Data.Length % 2 != 0)
                throw new InvalidDataException("Snapshot does not contain at least 36 elements, or contains an odd number of elements");

            // Assign server name and prefix
            this.ServerPrefix = Data[0];
            this.ServerName = Data[1];

            // Determine if we are central update. the "cdb_update" variable must be the LAST sector in snapshot
            int Mode;
            if (Data[Data.Length - 2] == "cdb_update" && Int32.TryParse(Data[Data.Length - 1], out Mode) && Mode.InRange(1, 2))
            {
                this.SnapshotMode = (Mode == 2) ? SnapshotMode.Minimal : SnapshotMode.FullSync;
            }

            // Setup our data dictionary's. We use NiceDictionary so we can easily determine missing keys in the log file
            NiceDictionary<string, string> StandardData = new NiceDictionary<string, string>(16);
            NiceDictionary<string, string> PlayerData = new NiceDictionary<string, string>();
            Dictionary<int, int> KillData = new Dictionary<int, int>();

            // Wrap parsing Key/Value snapshot data in a try block!
            try
            {
                // Convert our standard data into key => value pairs
                for (int i = 2; i < Data.Length; i += 2)
                {
                    // Format: "DataKey_PlayerIndex". PlayerIndex is NOT the Player Id
                    string[] Parts = Data[i].Split('_');
                    if (Parts.Length == 1)
                    {
                        // Add to the Standard keys
                        StandardData.Add(Data[i], Data[i + 1]);

                        // Are we at the End of File? If so stop here
                        if (Parts[0] == "EOF")
                        {
                            // Make sure to save that last players stats!!
                            if (PlayerData.Count != 0)
                            {
                                AddPlayer(new Player(PlayerData, KillData));
                                PlayerData = null;
                                KillData = null;
                            }
                            break;
                        }
                    }

                    // If the item key is "pID", then we have a new player record
                    else if (Parts[0] == "pID")
                    {
                        // If we have data, complete this player and start anew
                        if (PlayerData.Count != 0)
                        {
                            AddPlayer(new Player(PlayerData, KillData));
                            PlayerData.Clear();
                            KillData.Clear();
                        }

                        // Add new PID
                        PlayerData.Add(Parts[0], Data[i + 1]);
                    }
                    else if (Parts[0] == "mvks") // Skip mvks... kill data only needs processed once (mvns)
                        continue;
                    else if (Parts[0] == "mvns") // Player kill data
                        KillData.Add(Int32.Parse(Data[i + 1]), Int32.Parse(Data[i + 3]));
                    else
                        PlayerData.Add(Parts[0], Data[i + 1]);
                }
            }
            catch (Exception e)
            {
                throw new InvalidDataException("Error assigning Key => value pairs. See InnerException", e);
            }

            // Make sure we have a completed snapshot
            if (!StandardData.ContainsKey("EOF"))
                throw new InvalidDataException("No End of File element was found, Snapshot assumed to be incomplete.");

            // Try and set internal GameResult variables
            try
            {
                // Server data
                this.ServerPort = Int32.Parse(StandardData["gameport"]);
                this.QueryPort = Int32.Parse(StandardData["queryport"]);

                // Map Data
                this.MapName = StandardData["mapname"];
                this.MapId = Int32.Parse(StandardData["mapid"]);
                this.RoundStartTime = (int)Convert.ToDouble(StandardData["mapstart"], CultureInfo.InvariantCulture.NumberFormat);
                this.RoundEndTime = (int)Convert.ToDouble(StandardData["mapend"], CultureInfo.InvariantCulture.NumberFormat);

                // Misc Data
                this.GameMode = Int32.Parse(StandardData["gm"]);
                this.Mod = StandardData["v"]; // bf2 mod replaced the version key, since we dont care the version anyways
                this.PlayersConnected = Int32.Parse(StandardData["pc"]);

                // Army Data... There is no RWA key if there was no winner...
                this.WinningTeam = Int32.Parse(StandardData["win"]); // Temp
                this.WinningArmyId = (StandardData.ContainsKey("rwa")) ? Int32.Parse(StandardData["rwa"]) : -1;
                this.Team1ArmyId = Int32.Parse(StandardData["ra1"]);
                this.Team1Tickets = Int32.Parse(StandardData["rs1"]);
                this.Team2ArmyId = Int32.Parse(StandardData["ra2"]);
                this.Team2Tickets = Int32.Parse(StandardData["rs2"]);
            }
            catch (Exception e)
            {
                throw new InvalidDataException("Error assigning GameResult variables. See InnerException", e);
            }

            // Wrap this in a try-catch block, because we want to be able to view GameResult
            // data, even if the database is offline
            try
            {
                // Dispose when done!
                using (StatsDatabase Driver = new StatsDatabase())
                {
                    // Check for custom map, with no ID (Not defined in Constants.py)
                    if (this.MapId == 99)
                    {
                        // Check for existing map data
                        var Rows = Driver.Query("SELECT id FROM mapinfo WHERE name=@P0", this.MapName);
                        if (Rows.Count == 0)
                        {
                            // Create new MapId. Id's 700 - 1000 are reserved for unknown maps in the Constants.py file
                            // There should never be more then 300 unknown map id's, considering 1001 is the start of KNOWN
                            // Custom mod map id's. If we are at 1000 now, then we are in trouble :S
                            this.MapId = Driver.ExecuteScalar<int>("SELECT COALESCE(MAX(id), 699) FROM mapinfo WHERE id BETWEEN 700 AND 999") + 1;
                            if (this.MapId == 1000)
                                throw new Exception("Maximum unknown custom mapid has been reached. Please add this map's mapid to the Constants.py");

                            // Insert map data, so we dont lose this mapid we generated
                            Driver.Execute("INSERT INTO mapinfo(id, name, custom) VALUES (@P0, @P1, @P2)", this.MapId, this.MapName, 1);
                        }
                        else
                            this.MapId = Int32.Parse(Rows[0]["id"].ToString());
                    }

                    // Set whether or not this data is already been processed. The OR condition is because i goofed in early updates
                    // and set the timestamp to the RoundStart instead of the RoundEnd like i should have
                    this.IsProcessed = Driver.ExecuteScalar<int>(
                        "SELECT COUNT(*) FROM round_history WHERE mapid=@P0 AND time=@P1 AND (timestamp=@P2 OR timestamp=@P3)",
                        this.MapId, this.RoundTime.Seconds, this.RoundEndTime, this.RoundStartTime
                    ) > 0;
                }
            }
            catch(DbConnectException)
            {
                this.IsProcessed = false;
            }

            // Indicate whether we are a custom map
            this.IsCustomMap = (this.MapId >= 700 || this.MapId == 99);
        }
Esempio n. 15
0
        /// <summary>
        /// Processes the snapshot data, inserted and updating player data in the gamespy database
        /// </summary>
        /// <exception cref="InvalidDataException">Thrown if the snapshot data is invalid</exception>
        public void ProcessData()
        {
            // Make sure we are processing the same data again
            if (this.IsProcessed)
                throw new Exception("Round data has already been processed!");

            // Begin Logging
            Log(String.Format("Begin Processing ({0})...", this.MapName), LogLevel.Notice);
            Log(String.Format((this.IsCustomMap) ? "Custom Map ({0})..." : "Standard Map ({0})...", this.MapId), LogLevel.Notice);
            Log("Found " + this.Players.Count + " Player(s)...", LogLevel.Notice);

            // Make sure we meet the minimum player requirement
            if (this.Players.Count < Program.Config.ASP_MinRoundPlayers)
            {
                Log("Minimum round Player count does not meet the ASP requirement... Aborting", LogLevel.Warning);
                throw new Exception("Minimum round Player count does not meet the ASP requirement");
            }

            // CDB update
            if (this.SnapshotMode == SnapshotMode.Minimal)
                Log("Snapshot mode set to CentralDatabase.Minimal. Rank and Award data will be ingnored", LogLevel.Notice);

            // Setup some variables
            Stopwatch Clock = Stopwatch.StartNew();
            List<Dictionary<string, object>> Rows;
            InsertQueryBuilder InsertQuery;
            UpdateQueryBuilder UpdateQuery;
            WhereClause Where;

            // Start the timer and Begin Transaction
            using (StatsDatabase Driver = new StatsDatabase())
            using (DbTransaction Transaction = Driver.BeginTransaction())
            {
                // To prevent half complete snapshots due to exceptions,
                // Put the whole thing in a try block, and rollback on error
                try
                {
                    // Loop through each player, and process them
                    foreach (Player Player in this.Players)
                    {
                        // Player meets min round time or are we ignoring AI?
                        if ((Player.RoundTime < Program.Config.ASP_MinRoundTime) || (Program.Config.ASP_IgnoreAI && Player.IsAI))
                            continue;

                        // Parse some player data
                        bool OnWinningTeam = (Player.Team == WinningTeam);
                        string CountryCode = Ip2nation.GetCountryCode(Player.IpAddress);
                        int Best, Worst;

                        // Log
                        Log(String.Format("Processing Player ({0})", Player.Pid), LogLevel.Notice);

                        // Fetch the player
                        Rows = Driver.Query("SELECT ip, country, rank, killstreak, deathstreak, rndscore FROM player WHERE id=@P0", Player.Pid);
                        if (Rows.Count == 0)
                        {
                            // === New Player === //
                            Log(String.Format("Adding NEW Player ({0})", Player.Pid), LogLevel.Notice);

                            // We dont save rank data on CentralDatabase.Minimal
                            if (this.SnapshotMode == SnapshotMode.Minimal)
                                Player.SetRank(0);

                            // Build insert data
                            InsertQuery = new InsertQueryBuilder("player", Driver);
                            InsertQuery.SetField("id", Player.Pid);
                            InsertQuery.SetField("name", Player.Name);
                            InsertQuery.SetField("country", CountryCode);
                            InsertQuery.SetField("time", Player.RoundTime);
                            InsertQuery.SetField("rounds", Player.CompletedRound);
                            InsertQuery.SetField("ip", Player.IpAddress);
                            InsertQuery.SetField("score", Player.RoundScore);
                            InsertQuery.SetField("cmdscore", Player.CommandScore);
                            InsertQuery.SetField("skillscore", Player.SkillScore);
                            InsertQuery.SetField("teamscore", Player.TeamScore);
                            InsertQuery.SetField("kills", Player.Stats.Kills);
                            InsertQuery.SetField("deaths", Player.Stats.Deaths);
                            InsertQuery.SetField("captures", Player.Stats.FlagCaptures);
                            InsertQuery.SetField("captureassists", Player.Stats.FlagCaptureAssists);
                            InsertQuery.SetField("defends", Player.Stats.FlagDefends);
                            InsertQuery.SetField("damageassists", Player.Stats.DamageAssists);
                            InsertQuery.SetField("heals", Player.Stats.Heals);
                            InsertQuery.SetField("revives", Player.Stats.Revives);
                            InsertQuery.SetField("ammos", Player.Stats.Ammos);
                            InsertQuery.SetField("repairs", Player.Stats.Repairs);
                            InsertQuery.SetField("targetassists", Player.Stats.TargetAssists);
                            InsertQuery.SetField("driverspecials", Player.Stats.DriverSpecials);
                            InsertQuery.SetField("teamkills", Player.Stats.TeamKills);
                            InsertQuery.SetField("teamdamage", Player.Stats.TeamDamage);
                            InsertQuery.SetField("teamvehicledamage", Player.Stats.TeamVehicleDamage);
                            InsertQuery.SetField("suicides", Player.Stats.Suicides);
                            InsertQuery.SetField("killstreak", Player.Stats.KillStreak);
                            InsertQuery.SetField("deathstreak", Player.Stats.DeathStreak);
                            InsertQuery.SetField("rank", Player.Rank);
                            InsertQuery.SetField("banned", Player.TimesBanned);
                            InsertQuery.SetField("kicked", Player.TimesKicked);
                            InsertQuery.SetField("cmdtime", Player.CmdTime);
                            InsertQuery.SetField("sqltime", Player.SqlTime);
                            InsertQuery.SetField("sqmtime", Player.SqmTime);
                            InsertQuery.SetField("lwtime", Player.LwTime);
                            InsertQuery.SetField("wins", OnWinningTeam);
                            InsertQuery.SetField("losses", !OnWinningTeam);
                            InsertQuery.SetField("availunlocks", 0);
                            InsertQuery.SetField("usedunlocks", 0);
                            InsertQuery.SetField("joined", this.RoundEndTime);
                            InsertQuery.SetField("rndscore", Player.RoundScore);
                            InsertQuery.SetField("lastonline", RoundEndTime);
                            InsertQuery.SetField("mode0", (GameMode == 0));
                            InsertQuery.SetField("mode1", (GameMode == 1));
                            InsertQuery.SetField("mode2", (GameMode == 2));
                            InsertQuery.SetField("isbot", Player.IsAI);

                            // Insert Player Data
                            InsertQuery.Execute();

                            // Double Check Unlocks
                            if (!Player.IsAI && Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM unlocks WHERE id=@P0", Player.Pid) == 0)
                            {
                                // Create New Player Unlock Data
                                StringBuilder Q = new StringBuilder("INSERT INTO unlocks VALUES ", 350);

                                // Normal unlocks
                                for (int i = 11; i < 100; i += 11)
                                    Q.AppendFormat("({0}, {1}, 'n'), ", Player.Pid, i);

                                // Sf Unlocks
                                for (int i = 111; i < 556; i += 111)
                                {
                                    Q.AppendFormat("({0}, {1}, 'n')", Player.Pid, i);
                                    if (i != 555) Q.Append(", ");
                                }

                                // Execute query
                                Driver.Execute(Q.ToString());
                            }
                        }
                        else
                        {
                            // Existing Player
                            Log(String.Format("Updating EXISTING Player ({0})", Player.Pid), LogLevel.Notice);

                            // If rank is lower then the database rank, and the players old rank is not a special rank
                            // then we will be correct the rank here. We do this because sometimes stats are interupted
                            // while being fetched in the python (yay single threading!), and the players stats are reset
                            // during that round.
                            int DbRank = Int32.Parse(Rows[0]["rank"].ToString());
                            if (this.SnapshotMode == SnapshotMode.Minimal)
                            {
                                // On CDB mode, always use database rank
                                Player.SetRank(DbRank);
                            }
                            else if (DbRank > Player.Rank && DbRank != 11 && DbRank != 21)
                            {
                                // Fail-safe in-case rank data was not obtained and reset to '0' in-game.
                                Player.SetRank(DbRank);
                                DebugLog.Write("Rank Correction ({0}), Using database rank ({1})", Player.Pid, DbRank);
                            }

                            // Calcuate best killstreak/deathstreak
                            int KillStreak = Int32.Parse(Rows[0]["killstreak"].ToString());
                            int DeathStreak = Int32.Parse(Rows[0]["deathstreak"].ToString());
                            if (Player.Stats.KillStreak > KillStreak) KillStreak = Player.Stats.KillStreak;
                            if (Player.Stats.DeathStreak > DeathStreak) DeathStreak = Player.Stats.DeathStreak;

                            // Calculate Best Round Score
                            int Brs = Int32.Parse(Rows[0]["rndscore"].ToString());
                            if (Player.RoundScore > Brs) Brs = Player.RoundScore;

                            // Update Player Data
                            UpdateQuery = new UpdateQueryBuilder("player", Driver);
                            UpdateQuery.SetField("country", CountryCode, ValueMode.Set);
                            UpdateQuery.SetField("time", Player.RoundTime, ValueMode.Add);
                            UpdateQuery.SetField("rounds", Player.CompletedRound, ValueMode.Add);
                            UpdateQuery.SetField("ip", Player.IpAddress, ValueMode.Set);
                            UpdateQuery.SetField("score", Player.RoundScore, ValueMode.Add);
                            UpdateQuery.SetField("cmdscore", Player.CommandScore, ValueMode.Add);
                            UpdateQuery.SetField("skillscore", Player.SkillScore, ValueMode.Add);
                            UpdateQuery.SetField("teamscore", Player.TeamScore, ValueMode.Add);
                            UpdateQuery.SetField("kills", Player.Stats.Kills, ValueMode.Add);
                            UpdateQuery.SetField("deaths", Player.Stats.Deaths, ValueMode.Add);
                            UpdateQuery.SetField("captures", Player.Stats.FlagCaptures, ValueMode.Add);
                            UpdateQuery.SetField("captureassists", Player.Stats.FlagCaptureAssists, ValueMode.Add);
                            UpdateQuery.SetField("defends", Player.Stats.FlagDefends, ValueMode.Add);
                            UpdateQuery.SetField("damageassists", Player.Stats.DamageAssists, ValueMode.Add);
                            UpdateQuery.SetField("heals", Player.Stats.Heals, ValueMode.Add);
                            UpdateQuery.SetField("revives", Player.Stats.Revives, ValueMode.Add);
                            UpdateQuery.SetField("ammos", Player.Stats.Ammos, ValueMode.Add);
                            UpdateQuery.SetField("repairs", Player.Stats.Repairs, ValueMode.Add);
                            UpdateQuery.SetField("targetassists", Player.Stats.TargetAssists, ValueMode.Add);
                            UpdateQuery.SetField("driverspecials", Player.Stats.DriverSpecials, ValueMode.Add);
                            UpdateQuery.SetField("teamkills", Player.Stats.TeamKills, ValueMode.Add);
                            UpdateQuery.SetField("teamdamage", Player.Stats.TeamDamage, ValueMode.Add);
                            UpdateQuery.SetField("teamvehicledamage", Player.Stats.TeamVehicleDamage, ValueMode.Add);
                            UpdateQuery.SetField("suicides", Player.Stats.Suicides, ValueMode.Add);
                            UpdateQuery.SetField("Killstreak", KillStreak, ValueMode.Set);
                            UpdateQuery.SetField("deathstreak", DeathStreak, ValueMode.Set);
                            UpdateQuery.SetField("rank", Player.Rank, ValueMode.Set);
                            UpdateQuery.SetField("banned", Player.TimesBanned, ValueMode.Add);
                            UpdateQuery.SetField("kicked", Player.TimesKicked, ValueMode.Add);
                            UpdateQuery.SetField("cmdtime", Player.CmdTime, ValueMode.Add);
                            UpdateQuery.SetField("sqltime", Player.SqlTime, ValueMode.Add);
                            UpdateQuery.SetField("sqmtime", Player.SqmTime, ValueMode.Add);
                            UpdateQuery.SetField("lwtime", Player.LwTime, ValueMode.Add);
                            UpdateQuery.SetField("wins", OnWinningTeam, ValueMode.Add);
                            UpdateQuery.SetField("losses", !OnWinningTeam, ValueMode.Add);
                            UpdateQuery.SetField("rndscore", Brs, ValueMode.Set);
                            UpdateQuery.SetField("lastonline", this.RoundEndTime, ValueMode.Set);
                            UpdateQuery.SetField("mode0", (GameMode == 0), ValueMode.Add);
                            UpdateQuery.SetField("mode1", (GameMode == 1), ValueMode.Add);
                            UpdateQuery.SetField("mode2", (GameMode == 2), ValueMode.Add);
                            UpdateQuery.SetField("chng", (Player.Rank > DbRank), ValueMode.Set);
                            UpdateQuery.SetField("decr", (Player.Rank < DbRank), ValueMode.Set);
                            UpdateQuery.SetField("isbot", Player.IsAI, ValueMode.Set);
                            UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                            UpdateQuery.Execute();
                        }

                        // ********************************
                        // Insert Player history.
                        // ********************************
                        Driver.Execute(
                            "INSERT INTO player_history VALUES(@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9)",
                            Player.Pid, this.RoundEndTime, Player.RoundTime, Player.RoundScore, Player.CommandScore,
                            Player.SkillScore, Player.TeamScore, Player.Stats.Kills, Player.Stats.Deaths, Player.Rank
                        );

                        // ********************************
                        // Process Player Army Data
                        // ********************************
                        Log(String.Format("Processing Army Data ({0})", Player.Pid), LogLevel.Notice);

                        // Update player army times
                        Rows = Driver.Query("SELECT * FROM army WHERE id=" + Player.Pid);
                        if (Rows.Count == 0)
                        {
                            // Build query
                            InsertQuery = new InsertQueryBuilder("army", Driver);
                            InsertQuery.SetField("id", Player.Pid);
                            for (int i = 0; i < 14; i++)
                                InsertQuery.SetField("time" + i, Player.TimeAsArmy[i]);

                            // Make sure we arent playing an unsupported army
                            if (Player.ArmyId < 14)
                            {
                                InsertQuery.SetField("win" + Player.ArmyId, OnWinningTeam);
                                InsertQuery.SetField("loss" + Player.ArmyId, !OnWinningTeam);
                                InsertQuery.SetField("score" + Player.ArmyId, Player.RoundScore);
                                InsertQuery.SetField("best" + Player.ArmyId, Player.RoundScore);
                                InsertQuery.SetField("worst" + Player.ArmyId, Player.RoundScore);
                            }

                            InsertQuery.Execute();
                        }
                        else
                        {
                            // Build query
                            UpdateQuery = new UpdateQueryBuilder("army", Driver);
                            UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                            for (int i = 0; i < 14; i++)
                                UpdateQuery.SetField("time" + i, Player.TimeAsArmy[i], ValueMode.Add);

                            // Prevent database errors with custom army IDs
                            if (Player.ArmyId < 14)
                            {
                                Best = Int32.Parse(Rows[0]["best" + Player.ArmyId].ToString());
                                Worst = Int32.Parse(Rows[0]["worst" + Player.ArmyId].ToString());
                                if (Player.RoundScore > Best) Best = Player.RoundScore;
                                if (Player.RoundScore < Worst) Worst = Player.RoundScore;

                                UpdateQuery.SetField("win" + Player.ArmyId, OnWinningTeam, ValueMode.Add);
                                UpdateQuery.SetField("loss" + Player.ArmyId, !OnWinningTeam, ValueMode.Add);
                                UpdateQuery.SetField("score" + Player.ArmyId, Player.RoundScore, ValueMode.Add);
                                UpdateQuery.SetField("best" + Player.ArmyId, Best, ValueMode.Set);
                                UpdateQuery.SetField("worst" + Player.ArmyId, Worst, ValueMode.Set);
                            }

                            UpdateQuery.Execute();
                        }

                        // ********************************
                        // Process Player Kills
                        // ********************************
                        Log(String.Format("Processing Kills Data ({0})", Player.Pid), LogLevel.Notice);
                        foreach (KeyValuePair<int, int> Kill in Player.Victims)
                        {
                            // Kill: VictimPid => KillCount
                            if (Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM kills WHERE attacker=@P0 AND victim=@P1", Player.Pid, Kill.Key) == 0)
                            {
                                InsertQuery = new InsertQueryBuilder("kills", Driver);
                                InsertQuery.SetField("attacker", Player.Pid);
                                InsertQuery.SetField("victim", Kill.Key);
                                InsertQuery.SetField("count", Kill.Value);
                                InsertQuery.Execute();
                            }
                            else
                            {
                                UpdateQuery = new UpdateQueryBuilder("kills", Driver);
                                UpdateQuery.SetField("count", Kill.Value, ValueMode.Add);
                                Where = UpdateQuery.AddWhere("attacker", Comparison.Equals, Player.Pid);
                                Where.AddClause(LogicOperator.And, "victim", Comparison.Equals, Kill.Key);
                                UpdateQuery.Execute();
                            }
                        }

                        // ********************************
                        // Process Player Kit Data
                        // ********************************
                        Log(String.Format("Processing Kit Data ({0})", Player.Pid), LogLevel.Notice);

                        // Check for existing player data
                        if (Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM kits WHERE id=" + Player.Pid) == 0)
                        {
                            InsertQuery = new InsertQueryBuilder("kits", Driver);
                            InsertQuery.SetField("id", Player.Pid);
                            for (int i = 0; i < 7; i++)
                            {
                                InsertQuery.SetField("time" + i, Player.KitData[i].Time);
                                InsertQuery.SetField("kills" + i, Player.KitData[i].Kills);
                                InsertQuery.SetField("deaths" + i, Player.KitData[i].Deaths);
                            }
                            InsertQuery.Execute();
                        }
                        else
                        {
                            UpdateQuery = new UpdateQueryBuilder("kits", Driver);
                            UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                            for (int i = 0; i < 7; i++)
                            {
                                UpdateQuery.SetField("time" + i, Player.KitData[i].Time, ValueMode.Add);
                                UpdateQuery.SetField("kills" + i, Player.KitData[i].Kills, ValueMode.Add);
                                UpdateQuery.SetField("deaths" + i, Player.KitData[i].Deaths, ValueMode.Add);
                            }
                            UpdateQuery.Execute();
                        }

                        // ********************************
                        // Process Player Vehicle Data
                        // ********************************
                        Log(String.Format("Processing Vehicle Data ({0})", Player.Pid), LogLevel.Notice);

                        // Check for existing player data
                        if (Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM vehicles WHERE id=" + Player.Pid) == 0)
                        {
                            InsertQuery = new InsertQueryBuilder("vehicles", Driver);
                            InsertQuery.SetField("id", Player.Pid);
                            for (int i = 0; i < 7; i++)
                            {
                                InsertQuery.SetField("time" + i, Player.VehicleData[i].Time);
                                InsertQuery.SetField("kills" + i, Player.VehicleData[i].Kills);
                                InsertQuery.SetField("deaths" + i, Player.VehicleData[i].Deaths);
                                InsertQuery.SetField("rk" + i, Player.VehicleData[i].RoadKills);
                            }
                            InsertQuery.SetField("timepara", Player.VehicleData[7].Time);
                            InsertQuery.Execute();
                        }
                        else
                        {
                            UpdateQuery = new UpdateQueryBuilder("vehicles", Driver);
                            UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                            for (int i = 0; i < 7; i++)
                            {
                                UpdateQuery.SetField("time" + i, Player.VehicleData[i].Time, ValueMode.Add);
                                UpdateQuery.SetField("kills" + i, Player.VehicleData[i].Kills, ValueMode.Add);
                                UpdateQuery.SetField("deaths" + i, Player.VehicleData[i].Deaths, ValueMode.Add);
                                UpdateQuery.SetField("rk" + i, Player.VehicleData[i].RoadKills, ValueMode.Add);
                            }
                            UpdateQuery.SetField("timepara", Player.VehicleData[7].Time, ValueMode.Add);
                            UpdateQuery.Execute();
                        }

                        // ********************************
                        // Process Player Weapon Data
                        // ********************************
                        Log(String.Format("Processing Weapon Data ({0})", Player.Pid), LogLevel.Notice);

                        // Check for existing player data
                        if (Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM weapons WHERE id=" + Player.Pid) == 0)
                        {
                            // Prepare Query
                            InsertQuery = new InsertQueryBuilder("weapons", Driver);
                            InsertQuery.SetField("id", Player.Pid);

                            // Basic Weapon Data
                            for (int i = 0; i < 15; i++)
                            {
                                if (i < 9)
                                {
                                    InsertQuery.SetField("time" + i, Player.WeaponData[i].Time);
                                    InsertQuery.SetField("kills" + i, Player.WeaponData[i].Kills);
                                    InsertQuery.SetField("deaths" + i, Player.WeaponData[i].Deaths);
                                    InsertQuery.SetField("fired" + i, Player.WeaponData[i].Fired);
                                    InsertQuery.SetField("hit" + i, Player.WeaponData[i].Hits);
                                }
                                else
                                {
                                    string Pfx = GetWeaponTblPrefix(i);
                                    InsertQuery.SetField(Pfx + "time", Player.WeaponData[i].Time);
                                    InsertQuery.SetField(Pfx + "kills", Player.WeaponData[i].Kills);
                                    InsertQuery.SetField(Pfx + "deaths", Player.WeaponData[i].Deaths);
                                    InsertQuery.SetField(Pfx + "fired", Player.WeaponData[i].Fired);
                                    InsertQuery.SetField(Pfx + "hit", Player.WeaponData[i].Hits);
                                }
                            }

                            // Tactical
                            InsertQuery.SetField("tacticaltime", Player.WeaponData[15].Time);
                            InsertQuery.SetField("tacticaldeployed", Player.WeaponData[15].Deployed);

                            // Grappling Hook
                            InsertQuery.SetField("grapplinghooktime", Player.WeaponData[16].Time);
                            InsertQuery.SetField("grapplinghookdeployed", Player.WeaponData[16].Deployed);
                            InsertQuery.SetField("grapplinghookdeaths", Player.WeaponData[16].Deaths);

                            // Zipline
                            InsertQuery.SetField("ziplinetime", Player.WeaponData[17].Time);
                            InsertQuery.SetField("ziplinedeployed", Player.WeaponData[17].Deployed);
                            InsertQuery.SetField("ziplinedeaths", Player.WeaponData[17].Deaths);

                            // Do Query
                            InsertQuery.Execute();
                        }
                        else
                        {
                            // Prepare Query
                            UpdateQuery = new UpdateQueryBuilder("weapons", Driver);
                            UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);

                            // Basic Weapon Data
                            for (int i = 0; i < 15; i++)
                            {
                                if (i < 9)
                                {
                                    UpdateQuery.SetField("time" + i, Player.WeaponData[i].Time, ValueMode.Add);
                                    UpdateQuery.SetField("kills" + i, Player.WeaponData[i].Kills, ValueMode.Add);
                                    UpdateQuery.SetField("deaths" + i, Player.WeaponData[i].Deaths, ValueMode.Add);
                                    UpdateQuery.SetField("fired" + i, Player.WeaponData[i].Fired, ValueMode.Add);
                                    UpdateQuery.SetField("hit" + i, Player.WeaponData[i].Hits, ValueMode.Add);
                                }
                                else
                                {
                                    string Pfx = GetWeaponTblPrefix(i);
                                    UpdateQuery.SetField(Pfx + "time", Player.WeaponData[i].Time, ValueMode.Add);
                                    UpdateQuery.SetField(Pfx + "kills", Player.WeaponData[i].Kills, ValueMode.Add);
                                    UpdateQuery.SetField(Pfx + "deaths", Player.WeaponData[i].Deaths, ValueMode.Add);
                                    UpdateQuery.SetField(Pfx + "fired", Player.WeaponData[i].Fired, ValueMode.Add);
                                    UpdateQuery.SetField(Pfx + "hit", Player.WeaponData[i].Hits, ValueMode.Add);
                                }
                            }

                            // Tactical
                            UpdateQuery.SetField("tacticaltime", Player.WeaponData[15].Time, ValueMode.Add);
                            UpdateQuery.SetField("tacticaldeployed", Player.WeaponData[15].Deployed, ValueMode.Add);

                            // Grappling Hook
                            UpdateQuery.SetField("grapplinghooktime", Player.WeaponData[16].Time, ValueMode.Add);
                            UpdateQuery.SetField("grapplinghookdeployed", Player.WeaponData[16].Deployed, ValueMode.Add);
                            UpdateQuery.SetField("grapplinghookdeaths", Player.WeaponData[16].Deaths, ValueMode.Add);

                            // Zipline
                            UpdateQuery.SetField("ziplinetime", Player.WeaponData[17].Time, ValueMode.Add);
                            UpdateQuery.SetField("ziplinedeployed", Player.WeaponData[17].Deployed, ValueMode.Add);
                            UpdateQuery.SetField("ziplinedeaths", Player.WeaponData[17].Deaths, ValueMode.Add);

                            // Do Query
                            UpdateQuery.Execute();
                        }

                        // ********************************
                        // Process Player Map Data
                        // ********************************
                        Log(String.Format("Processing Map Data ({0})", Player.Pid), LogLevel.Notice);

                        Rows = Driver.Query("SELECT best, worst FROM maps WHERE id=@P0 AND mapid=@P1", Player.Pid, MapId);
                        if (Rows.Count == 0)
                        {
                            // Prepare Query
                            InsertQuery = new InsertQueryBuilder("maps", Driver);
                            InsertQuery.SetField("id", Player.Pid);
                            InsertQuery.SetField("mapid", this.MapId);
                            InsertQuery.SetField("time", Player.RoundTime);
                            InsertQuery.SetField("win", OnWinningTeam);
                            InsertQuery.SetField("loss", !OnWinningTeam);
                            InsertQuery.SetField("best", Player.RoundScore);
                            InsertQuery.SetField("worst", Player.RoundScore);
                            InsertQuery.Execute();
                        }
                        else
                        {
                            // Get best and worst round scores
                            Best = Int32.Parse(Rows[0]["best"].ToString());
                            Worst = Int32.Parse(Rows[0]["worst"].ToString());
                            if (Player.RoundScore > Best) Best = Player.RoundScore;
                            if (Player.RoundScore < Worst) Worst = Player.RoundScore;

                            // Prepare Query
                            UpdateQuery = new UpdateQueryBuilder("maps", Driver);
                            Where = UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                            Where.AddClause(LogicOperator.And, "mapid", Comparison.Equals, this.MapId);
                            UpdateQuery.SetField("time", Player.RoundTime, ValueMode.Add);
                            UpdateQuery.SetField("win", OnWinningTeam, ValueMode.Add);
                            UpdateQuery.SetField("loss", !OnWinningTeam, ValueMode.Add);
                            UpdateQuery.SetField("best", Best, ValueMode.Set);
                            UpdateQuery.SetField("worst", Worst, ValueMode.Set);
                            UpdateQuery.Execute();
                        }

                        // Quit here on central database Min mode, since award data isnt allowed
                        if (this.SnapshotMode == SnapshotMode.Minimal) continue;

                        // ********************************
                        // Process Player Awards Data
                        // ********************************
                        Log(String.Format("Processing Award Data ({0})", Player.Pid), LogLevel.Notice);

                        // Do we require round completion for award processing?
                        if (Player.CompletedRound || !Program.Config.ASP_AwardsReqComplete)
                        {
                            // Prepare query
                            InsertQuery = new InsertQueryBuilder("awards", Driver);

                            // Add Backend awards too
                            foreach (BackendAward Award in BackendAwardData.BackendAwards)
                            {
                                int Level = 1;
                                if (Award.CriteriaMet(Player.Pid, Driver, ref Level))
                                    Player.EarnedAwards.Add(Award.AwardId, Level);
                            }

                            // Now we loop though each players earned award, and store them in the database
                            foreach (KeyValuePair<int, int> Award in Player.EarnedAwards)
                            {
                                // Get our award type. Award.Key is the ID, Award.Value is the level (or count)
                                bool IsMedal = Award.Key.InRange(2000000, 3000000);
                                bool IsBadge = (Award.Key < 2000000);

                                // Build our query
                                string Query = "SELECT COUNT(*) FROM awards WHERE id=@P0 AND awd=@P1";
                                if (IsBadge)
                                    Query += " AND level=" + Award.Value.ToString();

                                // Check for prior awarding of award
                                if (Driver.ExecuteScalar<int>(Query, Player.Pid, Award.Key) == 0)
                                {
                                    // Need to do extra work for Badges as more than one badge level may have been awarded.
                                    // The snapshot will only post the highest awarded level of a badge, so here we award
                                    // the lower level badges if the player does not have them.
                                    if (IsBadge)
                                    {
                                        // Check all prior badge levels, and make sure the player has them
                                        for (int j = 1; j < Award.Value; j++)
                                        {
                                            Query = "SELECT COUNT(*) FROM awards WHERE id=@P0 AND awd=@P1 AND level=@P2";
                                            if (Driver.ExecuteScalar<int>(Query, Player.Pid, Award.Key, j) == 0)
                                            {
                                                // Prepare Query
                                                InsertQuery.SetField("id", Player.Pid);
                                                InsertQuery.SetField("awd", Award.Key);
                                                InsertQuery.SetField("level", j);
                                                InsertQuery.SetField("earned", (this.RoundEndTime - 5) + j);
                                                InsertQuery.SetField("first", 0);
                                                InsertQuery.Execute();
                                            }
                                        }
                                    }

                                    // Add the players award
                                    InsertQuery.SetField("id", Player.Pid);
                                    InsertQuery.SetField("awd", Award.Key);
                                    InsertQuery.SetField("level", Award.Value);
                                    InsertQuery.SetField("earned", this.RoundEndTime);
                                    InsertQuery.SetField("first", ((IsMedal) ? this.RoundEndTime : 0));
                                    InsertQuery.Execute();

                                }
                                else // === Player has recived this award prior === //
                                {
                                    // Only update medals because ribbons and badges are only awarded once ever!
                                    if (IsMedal)
                                    {
                                        // Prepare Query
                                        UpdateQuery = new UpdateQueryBuilder("awards", Driver);
                                        Where = UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                                        Where.AddClause(LogicOperator.And, "awd", Comparison.Equals, Award.Key);
                                        UpdateQuery.SetField("level", 1, ValueMode.Add);
                                        UpdateQuery.SetField("earned", this.RoundEndTime, ValueMode.Set);
                                        UpdateQuery.Execute();
                                    }
                                }

                                // Add best round count if player earned best round medal
                                if (Award.Key == 2051907 && Player.ArmyId < 14)
                                {
                                    // Prepare Query
                                    UpdateQuery = new UpdateQueryBuilder("army", Driver);
                                    UpdateQuery.AddWhere("id", Comparison.Equals, Player.Pid);
                                    UpdateQuery.SetField("brnd" + Player.ArmyId, 1, ValueMode.Add);
                                    UpdateQuery.Execute();
                                }

                            } // End Foreach Award
                        } // End Award Processing
                    } // End Foreach Player

                    // ********************************
                    // Process ServerInfo
                    // ********************************
                    //Log("Processing Game Server", LogLevel.Notice);

                    // ********************************
                    // Process MapInfo
                    // ********************************
                    Log(String.Format("Processing Map Info ({0}:{1})", this.MapName, this.MapId), LogLevel.Notice);
                    if (Driver.ExecuteScalar<int>("SELECT COUNT(*) FROM mapinfo WHERE id=" + this.MapId) == 0)
                    {
                        // Prepare Query
                        InsertQuery = new InsertQueryBuilder("mapinfo", Driver);
                        InsertQuery.SetField("id", this.MapId);
                        InsertQuery.SetField("name", this.MapName);
                        InsertQuery.SetField("score", this.MapScore);
                        InsertQuery.SetField("time", this.RoundTime.Seconds);
                        InsertQuery.SetField("times", 1);
                        InsertQuery.SetField("kills", this.MapKills);
                        InsertQuery.SetField("deaths", this.MapDeaths);
                        InsertQuery.SetField("custom", (this.IsCustomMap) ? 1 : 0);
                        InsertQuery.Execute();
                    }
                    else
                    {
                        UpdateQuery = new UpdateQueryBuilder("mapinfo", Driver);
                        UpdateQuery.AddWhere("id", Comparison.Equals, this.MapId);
                        UpdateQuery.SetField("score", this.MapScore, ValueMode.Add);
                        UpdateQuery.SetField("time", this.RoundTime.Seconds, ValueMode.Add);
                        UpdateQuery.SetField("times", 1, ValueMode.Add);
                        UpdateQuery.SetField("kills", this.MapKills, ValueMode.Add);
                        UpdateQuery.SetField("deaths", this.MapDeaths, ValueMode.Add);
                        UpdateQuery.Execute();
                    }

                    // ********************************
                    // Process RoundInfo
                    // ********************************
                    Log("Processing Round Info", LogLevel.Notice);
                    InsertQuery = new InsertQueryBuilder("round_history", Driver);
                    InsertQuery.SetField("timestamp", this.RoundEndTime);
                    InsertQuery.SetField("mapid", this.MapId);
                    InsertQuery.SetField("time", this.RoundTime.Seconds);
                    InsertQuery.SetField("team1", this.Team1ArmyId);
                    InsertQuery.SetField("team2", this.Team2ArmyId);
                    InsertQuery.SetField("tickets1", this.Team1Tickets);
                    InsertQuery.SetField("tickets2", this.Team2Tickets);
                    InsertQuery.SetField("pids1", this.Team1Players);
                    InsertQuery.SetField("pids1_end", this.Team1PlayersEnd);
                    InsertQuery.SetField("pids2", this.Team2Players);
                    InsertQuery.SetField("pids2_end", this.Team2PlayersEnd);
                    InsertQuery.Execute();

                    // ********************************
                    // Process Smoc And General Ranks
                    // ********************************
                    if (Program.Config.ASP_SmocCheck) SmocCheck(Driver);
                    if (Program.Config.ASP_GeneralCheck) GenCheck(Driver);

                    // ********************************
                    // Commit the Transaction and Log
                    // ********************************
                    Transaction.Commit();
                    Clock.Stop();

                    // Log in the stats debug log, and call it
                    this.IsProcessed = true;
                    string logText = String.Format(
                        "Snapshot ({0}) processed in {1} milliseconds [{2} Queries]",
                        this.MapName, Clock.Elapsed.Milliseconds, Driver.NumQueries
                    );
                    Log(logText, LogLevel.Info);
                }
                catch (Exception E)
                {
                    Log("An error occured while updating player stats: " + E.Message, LogLevel.Error);
                    ExceptionHandler.GenerateExceptionLog(E);
                    Transaction.Rollback();
                    throw;
                }
            }
        }
Esempio n. 16
0
        public override void HandleRequest()
        {
            // Setup Variables
            List<Dictionary<string, object>> Rows;
            Dictionary<string, string> QueryString = Request.QueryString;

            // Querystring vars
            int IsAI = 0;
            int ListPlayers = 0;
            string PlayerNick = "";

            // Setup Params
            if (QueryString.ContainsKey("nick"))
                PlayerNick = Uri.UnescapeDataString(QueryString["nick"].Replace("%20", " "));
            if (QueryString.ContainsKey("ai"))
                Int32.TryParse(QueryString["ai"], out IsAI);
            if (QueryString.ContainsKey("playerlist"))
                Int32.TryParse(QueryString["playerlist"], out ListPlayers);

            // NOTE: The HttpServer will handle the DbConnectException
            using (Database = new StatsDatabase())
            {
                // Handle Request
                if (!String.IsNullOrWhiteSpace(PlayerNick))
                {
                    int Pid;

                    // Create player if they donot exist
                    Rows = Database.Query("SELECT id FROM player WHERE name = @P0 LIMIT 1", PlayerNick);
                    if (Rows.Count == 0)
                    {
                        // Grab new Player ID using thread safe methods
                        Pid = (IsAI > 0) ? StatsManager.GenerateNewAIPid() : StatsManager.GenerateNewPlayerPid();

                        // Create Player
                        Database.Execute(
                            "INSERT INTO player(id, name, joined, isbot) VALUES(@P0, @P1, @P2, @P3)",
                            Pid, PlayerNick, DateTime.UtcNow.ToUnixTimestamp(), IsAI
                        );
                    }
                    else
                        Pid = Int32.Parse(Rows[0]["id"].ToString());

                    // Send Response
                    Response.WriteResponseStart();
                    Response.WriteHeaderLine("pid");
                    Response.WriteDataLine(Pid);
                }
                else if (ListPlayers != 0)
                {
                    // Prepare Response
                    Response.WriteResponseStart();
                    Response.WriteHeaderLine("pid");

                    // Fetch Players
                    Rows = Database.Query("SELECT id FROM player WHERE isbot=0 LIMIT 1000");
                    foreach (Dictionary<string, object> Player in Rows)
                        Response.WriteDataLine(Player["id"]);
                }
                else
                {
                    Response.WriteResponseStart(false);
                    Response.WriteHeaderLine("asof", "err");
                    Response.WriteDataLine(DateTime.UtcNow.ToUnixTimestamp(), "Invalid Syntax!");
                }

                // Send Response
                Response.Send();
            }
        }
        public override void HandleRequest()
        {
            // Get player ID
            if (Request.QueryString.ContainsKey("pid"))
                Int32.TryParse(Request.QueryString["pid"], out Pid);

            // Prepare Output
            Response.WriteResponseStart();
            Response.WriteHeaderLine("pid", "nick", "asof");

            // Our ourput changes based on the selected Unlocks config setting
            switch (Program.Config.ASP_UnlocksMode)
            {
                // Player Based - Unlocks are earned
                case 0:
                    // NOTE: The HttpServer will handle the DbConnectException
                    using (Database = new StatsDatabase())
                    {
                        // Make sure the player exists
                        Rows = Database.Query("SELECT name, score, rank, availunlocks, usedunlocks FROM player WHERE id=@P0", Pid);
                        if (Rows.Count == 0)
                            goto case 2; // No Unlocks

                        // Start Output
                        Response.WriteDataLine(Pid, Rows[0]["name"].ToString().Trim(), DateTime.UtcNow.ToUnixTimestamp());

                        // Get total number of unlocks player is allowed to have givin his rank, and bonus unlocks
                        Rank = Int32.Parse(Rows[0]["rank"].ToString());
                        int HasUsed = Int32.Parse(Rows[0]["usedunlocks"].ToString());
                        int Available = Int32.Parse(Rows[0]["availunlocks"].ToString());
                        int Earned = GetBonusUnlocks();

                        // Determine total unlocks available, based on what he has earned, minus what he has used already
                        int Used = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM unlocks WHERE id=@P0 AND state='s'", Pid);
                        Earned -= Used;

                        // Update database if the database is off
                        if (Earned != Available || HasUsed != Used)
                            Database.Execute("UPDATE player SET availunlocks=@P0, usedunlocks=@P1 WHERE id=@P2", Earned, Used, Pid);

                        // Output more
                        Response.WriteHeaderLine("enlisted", "officer");
                        Response.WriteDataLine(Earned, 0);
                        Response.WriteHeaderLine("id", "state");

                        // Add each unlock's state
                        Rows = Database.Query("SELECT kit, state FROM unlocks WHERE id=@P0 ORDER BY kit ASC", Pid);
                        if (Rows.Count == 0)
                        {
                            // Create Player Unlock Data
                            StringBuilder Query = new StringBuilder("INSERT INTO unlocks VALUES ", 350);

                            // Normal unlocks
                            for (int i = 11; i < 100; i += 11)
                            {
                                // 88 and above are Special Forces unlocks, and wont display at all if the base unlocks are not earned
                                if (i < 78)
                                    Response.WriteDataLine(i, "n");
                                Query.AppendFormat("({0}, {1}, 'n'), ", Pid, i);
                            }

                            // Sf Unlocks, Dont display these because thats how Gamespy does it
                            for (int i = 111; i < 556; i += 111)
                            {
                                Query.AppendFormat("({0}, {1}, 'n')", Pid, i);
                                if (i != 555)
                                    Query.Append(", ");
                            }

                            // Do Insert
                            Database.Execute(Query.ToString());
                        }
                        else
                        {
                            Dictionary<string, bool> Unlocks = new Dictionary<string, bool>(7);
                            foreach (Dictionary<string, object> Unlock in Rows)
                            {
                                // Add unlock to output if its a base unlock
                                int Id = Int32.Parse(Unlock["kit"].ToString());
                                if (Id < 78)
                                    Response.WriteDataLine(Unlock["kit"], Unlock["state"]);

                                // Add Unlock to list
                                Unlocks.Add(Unlock["kit"].ToString(), (Unlock["state"].ToString() == "s"));
                            }

                            // Add SF Unlocks... We need the base class unlock unlocked first
                            CheckUnlock(88, 22, Unlocks);
                            CheckUnlock(99, 33, Unlocks);
                            CheckUnlock(111, 44, Unlocks);
                            CheckUnlock(222, 55, Unlocks);
                            CheckUnlock(333, 66, Unlocks);
                            CheckUnlock(444, 11, Unlocks);
                            CheckUnlock(555, 77, Unlocks);
                        }
                    }
                    break;

                // All Unlocked
                case 1:
                    Response.WriteDataLine(Pid, "All_Unlocks", DateTime.UtcNow.ToUnixTimestamp());
                    Response.WriteHeaderLine("enlisted", "officer");
                    Response.WriteDataLine(0, 0);
                    Response.WriteHeaderLine("id", "state");
                    for (int i = 11; i < 100; i += 11)
                        Response.WriteDataLine(i, "s");
                    for (int i = 111; i < 556; i += 111)
                        Response.WriteDataLine(i, "s");
                    break;

                // Unlocks Disabled
                case 2:
                default:
                    Response.WriteDataLine(Pid, "No_Unlocks", DateTime.UtcNow.ToUnixTimestamp());
                    Response.WriteHeaderLine("enlisted", "officer");
                    Response.WriteDataLine(0, 0);
                    Response.WriteHeaderLine("id", "state");
                    for (int i = 11; i < 78; i += 11)
                        Response.WriteDataLine(i, "n");
                    break;
            }

            // Send Response
            Response.Send();
        }
        /// <summary>
        /// Imports ASP created BAK files (Mysql Out FILE)
        /// </summary>
        private void ImportASPBtn_Click(object sender, EventArgs e)
        {
            // Open File Select Dialog
            FolderSelectDialog Dialog = new FolderSelectDialog();
            Dialog.Title = "Select ASP Database Backup Folder";
            Dialog.InitialDirectory = Path.Combine(Paths.DocumentsFolder, "Backups");
            if (Dialog.ShowDialog())
            {
                // Get files list from path
                string path = Dialog.SelectedPath;
                string[] BakFiles = Directory.GetFiles(path, "*.bak");
                if (BakFiles.Length > 0)
                {
                    // Open the database connection
                    StatsDatabase Database;
                    try
                    {
                        Database = new StatsDatabase();
                    }
                    catch (Exception Ex)
                    {
                        MessageBox.Show(
                            "Unable to connect to database\r\n\r\nMessage: " + Ex.Message,
                            "Database Connection Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error
                        );

                        // Stop the ASP server, and close this form
                        ASP.ASPServer.Stop();
                        this.Close();
                        return;
                    }

                    // Show task dialog
                    TaskForm.Show(this, "Importing Stats", "Importing ASP Stats Bak Files...", false);
                    TaskForm.UpdateStatus("Removing old stats data");

                    // Clear old database records
                    Database.Truncate();
                    Thread.Sleep(500);

                    // Begin transaction
                    DbTransaction Transaction = Database.BeginTransaction();

                    // import each table
                    foreach (string file in BakFiles)
                    {
                        // Get table name
                        string table = Path.GetFileNameWithoutExtension(file);

                        // Update progress
                        TaskForm.UpdateStatus("Processing stats table: " + table);

                        // Import table data
                        try
                        {
                            // Sqlite kinda sucks... no import methods
                            if (Database.DatabaseEngine == DatabaseEngine.Sqlite)
                            {
                                string[] Lines = File.ReadAllLines(file);
                                foreach (string line in Lines)
                                {
                                    string[] Values = line.Split('\t');
                                    Database.Execute(
                                        String.Format("INSERT INTO {0} VALUES({1})", table, "\"" + String.Join("\", \"", Values) + "\"")
                                    );
                                }
                            }
                            else
                                Database.Execute(String.Format("LOAD DATA LOCAL INFILE '{0}' INTO TABLE {1};", file.Replace('\\', '/'), table));
                        }
                        catch (Exception Ex)
                        {
                            // Show exception error
                            ExceptionForm Form = new ExceptionForm(Ex, false);
                            Form.Message = String.Format("Failed to import data into table {0}!{2}{2}Error: {1}", table, Ex.Message, Environment.NewLine);
                            DialogResult Result = Form.ShowDialog();

                            // Rollback!
                            TaskForm.UpdateStatus("Rolling back stats data");
                            Transaction.Rollback();

                            // Update message
                            TaskForm.CloseForm();
                            return;
                        }
                    }

                    // Commit the transaction, and alert the user
                    Transaction.Commit();
                    TaskForm.CloseForm();
                    Notify.Show("Stats imported successfully!", "Operation Successful", AlertType.Success);

                    // Displose Connection
                    Database.Dispose();
                }
                else
                {
                    // Alert the user and tell them they failed
                    MessageBox.Show(
                        "Unable to locate any .bak files in this folder. Please select an ASP created database backup folder that contains backup files.",
                        "Backup Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error
                    );
                }
            }
        }
        /// <summary>
        /// This method imports a list of .Bak files into the database
        /// </summary>
        /// <param name="BakFiles">A list of Backfiles to import into the database</param>
        /// <param name="Database">The opened database connection</param>
        private void ImportFromBakup(string[] BakFiles, StatsDatabase Database)
        {
            // Clear old database records
            TaskForm.Progress.Report(new TaskProgressUpdate("Removing old stats data"));
            Database.Truncate();

            // Let the database update itself
            Thread.Sleep(500);

            // Begin transaction
            using (DbTransaction Transaction = Database.BeginTransaction())
            {
                // import each table
                foreach (string file in BakFiles)
                {
                    // Get table name
                    string table = Path.GetFileNameWithoutExtension(file);
                    TaskForm.Progress.Report(new TaskProgressUpdate("Processing stats table: " + table));

                    // Import table data
                    try
                    {
                        // Sqlite kinda sucks... no import methods
                        if (Database.DatabaseEngine == DatabaseEngine.Sqlite)
                        {
                            string[] Lines = File.ReadAllLines(file);
                            foreach (string line in Lines)
                            {
                                string[] Values = line.Split('\t');
                                Database.Execute(
                                    String.Format("INSERT INTO {0} VALUES({1})", table, "\"" + String.Join("\", \"", Values) + "\"")
                                );
                            }
                        }
                        else
                            Database.Execute(String.Format("LOAD DATA LOCAL INFILE '{0}' INTO TABLE {1};", file.Replace('\\', '/'), table));
                    }
                    catch (Exception Ex)
                    {
                        // Show exception error
                        using (ExceptionForm Form = new ExceptionForm(Ex, false))
                        {
                            Form.Message = String.Format("Failed to import data into table {0}!{2}{2}Error: {1}", table, Ex.Message, Environment.NewLine);
                            DialogResult Result = Form.ShowDialog();

                            // Rollback!
                            TaskForm.Progress.Report(new TaskProgressUpdate("Rolling back stats data"));
                            Transaction.Rollback();
                            return;
                        }
                    }
                }

                // Commit the transaction
                Transaction.Commit();
            }
        }