/// <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>
        /// Imports a Player XML Sheet from the specified path
        /// </summary>
        /// <param name="XmlPath">The full path to the XML file</param>
        public static void ImportPlayerXml(string XmlPath)
        {
            // Connect to database first!
            using (StatsDatabase Driver = new StatsDatabase())
            {
                // Load elements
                XDocument Doc = XDocument.Load(new FileStream(XmlPath, FileMode.Open, FileAccess.Read));
                XElement Info = Doc.Root.Element("Info");
                XElement TableData = Doc.Root.Element("TableData");

                // Make sure player doesnt already exist
                int Pid = Int32.Parse(Info.Element("Pid").Value);
                if (Driver.PlayerExists(Pid))
                    throw new Exception(String.Format("Player with PID {0} already exists!", Pid));

                // Begin Transaction
                using (DbTransaction Transaction = Driver.BeginTransaction())
                {
                    try
                    {
                        // Loop through tables
                        foreach (XElement Table in TableData.Elements())
                        {
                            // Loop through Rows
                            foreach (XElement Row in Table.Elements())
                            {
                                InsertQueryBuilder QueryBuilder = new InsertQueryBuilder(Table.Name.LocalName, Driver);
                                foreach (XElement Col in Row.Elements())
                                {
                                    if (Col.Name.LocalName == "name")
                                        QueryBuilder.SetField(Col.Name.LocalName, Col.Value.UnescapeXML());
                                    else
                                        QueryBuilder.SetField(Col.Name.LocalName, Col.Value);
                                }

                                QueryBuilder.Execute();
                            }
                        }

                        // Commit Transaction
                        Transaction.Commit();
                    }
                    catch
                    {
                        Transaction.Rollback();
                        throw;
                    }
                }
            }
        }
        /// <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();
            }
        }
        /// <summary>
        /// Imports a players stats from the official gamespy ASP.
        /// This method is to be used in a background worker
        /// </summary>
        public void bWorker_ImportEaStats(object sender, DoWorkEventArgs e)
        {
            // Setup variables
            BackgroundWorker Worker = (BackgroundWorker)sender;
            int Pid = Int32.Parse(e.Argument.ToString());

            // Do work
            using (StatsDatabase Driver = new StatsDatabase())
            {
                // Make sure the player doesnt exist!
                if (Driver.PlayerExists(Pid))
                    throw new Exception(String.Format("Player with PID {0} already exists!", Pid));

                // Build variables
                Uri GsUrl;
                WebRequest Request;
                HttpWebResponse Response;
                List<string[]> PlayerLines;
                List<string[]> AwardLines;
                List<string[]> MapLines;
                InsertQueryBuilder Query;

                // Create Request
                string Url = String.Format(
                    "getplayerinfo.aspx?pid={0}&info=per*,cmb*,twsc,cpcp,cacp,dfcp,kila,heal,rviv,rsup,rpar,tgte,dkas,dsab,cdsc,rank,cmsc,kick,kill,deth,suic,"
                    + "ospm,klpm,klpr,dtpr,bksk,wdsk,bbrs,tcdr,ban,dtpm,lbtl,osaa,vrk,tsql,tsqm,tlwf,mvks,vmks,mvn*,vmr*,fkit,fmap,fveh,fwea,wtm-,wkl-,wdt-,"
                    + "wac-,wkd-,vtm-,vkl-,vdt-,vkd-,vkr-,atm-,awn-,alo-,abr-,ktm-,kkl-,kdt-,kkd-",
                    Pid);
                Worker.ReportProgress(1, "Requesting Player Stats");
                GsUrl = new Uri("http://bf2web.gamespy.com/ASP/" + Url);
                Request = WebRequest.Create(GsUrl);

                // Get response
                Response = (HttpWebResponse)Request.GetResponse();
                if (Response.StatusCode != HttpStatusCode.OK)
                    throw new Exception("Unable to connect to the Gamespy ASP Webservice!");

                // Read response data
                Worker.ReportProgress(2, "Parsing Stats Response");
                PlayerLines = new List<string[]>();
                using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                    while (!Reader.EndOfStream)
                        PlayerLines.Add(Reader.ReadLine().Split('\t'));

                // Does the player exist?
                if (PlayerLines[0][0] != "O")
                    throw new Exception("Player does not exist on the gamespy servers!");

                // Fetch player mapinfo
                Worker.ReportProgress(3, "Requesting Player Map Data");
                GsUrl = new Uri(String.Format("http://bf2web.gamespy.com/ASP/getplayerinfo.aspx?pid={0}&info=mtm-,mwn-,mls-", Pid));
                Request = WebRequest.Create(GsUrl);

                // Get response
                Response = (HttpWebResponse)Request.GetResponse();
                if (Response.StatusCode != HttpStatusCode.OK)
                    throw new Exception("Unable to connect to the Gamespy ASP Webservice!");

                // Read response data
                Worker.ReportProgress(4, "Parsing Map Data Response");
                MapLines = new List<string[]>();
                using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                    while (!Reader.EndOfStream)
                        MapLines.Add(Reader.ReadLine().Split('\t'));

                // Fetch player awards
                Worker.ReportProgress(5, "Requesting Player Awards");
                GsUrl = new Uri(String.Format("http://bf2web.gamespy.com/ASP/getawardsinfo.aspx?pid={0}", Pid));
                Request = WebRequest.Create(GsUrl);

                // Get response
                Response = (HttpWebResponse)Request.GetResponse();
                if (Response.StatusCode != HttpStatusCode.OK)
                    throw new Exception("Unable to connect to the Gamespy ASP Webservice!");

                // Read response data
                Worker.ReportProgress(6, "Parsing Player Awards Response");
                AwardLines = new List<string[]>();
                using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
                    while (!Reader.EndOfStream)
                        AwardLines.Add(Reader.ReadLine().Split('\t'));

                // === Process Player Info === //

                // Parse Player Data
                Dictionary<string, string> PlayerInfo = StatsParser.ParseHeaderData(PlayerLines[3], PlayerLines[4]);
                int Rounds = Int32.Parse(PlayerInfo["mode0"]) + Int32.Parse(PlayerInfo["mode1"]) + Int32.Parse(PlayerInfo["mode2"]);

                // Begin database transaction
                DbTransaction Transaction = Driver.BeginTransaction();

                // Wrap all DB inserts into a try block so we can rollback on error
                try
                {
                    // Insert Player Data
                    Worker.ReportProgress(7, "Inserting Player Data Into Table: player");
                    Query = new InsertQueryBuilder("player", Driver);
                    Query.SetField("id", Pid);
                    Query.SetField("name", " " + PlayerInfo["nick"].Trim()); // Online accounts always start with space in bf2stats
                    Query.SetField("country", "xx");
                    Query.SetField("time", PlayerInfo["time"]);
                    Query.SetField("rounds", Rounds);
                    Query.SetField("ip", "127.0.0.1");
                    Query.SetField("score", PlayerInfo["scor"]);
                    Query.SetField("cmdscore", PlayerInfo["cdsc"]);
                    Query.SetField("skillscore", PlayerInfo["cmsc"]);
                    Query.SetField("teamscore", PlayerInfo["twsc"]);
                    Query.SetField("kills", PlayerInfo["kill"]);
                    Query.SetField("deaths", PlayerInfo["deth"]);
                    Query.SetField("captures", PlayerInfo["cpcp"]);
                    Query.SetField("captureassists", PlayerInfo["cacp"]);
                    Query.SetField("defends", PlayerInfo["dfcp"]);
                    Query.SetField("damageassists", PlayerInfo["kila"]);
                    Query.SetField("heals", PlayerInfo["heal"]);
                    Query.SetField("revives", PlayerInfo["rviv"]);
                    Query.SetField("ammos", PlayerInfo["rsup"]);
                    Query.SetField("repairs", PlayerInfo["rpar"]);
                    Query.SetField("driverspecials", PlayerInfo["dsab"]);
                    Query.SetField("suicides", PlayerInfo["suic"]);
                    Query.SetField("killstreak", PlayerInfo["bksk"]);
                    Query.SetField("deathstreak", PlayerInfo["wdsk"]);
                    Query.SetField("rank", PlayerInfo["rank"]);
                    Query.SetField("banned", PlayerInfo["ban"]);
                    Query.SetField("kicked", PlayerInfo["kick"]);
                    Query.SetField("cmdtime", PlayerInfo["tcdr"]);
                    Query.SetField("sqltime", PlayerInfo["tsql"]);
                    Query.SetField("sqmtime", PlayerInfo["tsqm"]);
                    Query.SetField("lwtime", PlayerInfo["tlwf"]);
                    Query.SetField("wins", PlayerInfo["wins"]);
                    Query.SetField("losses", PlayerInfo["loss"]);
                    Query.SetField("joined", PlayerInfo["jond"]);
                    Query.SetField("rndscore", PlayerInfo["bbrs"]);
                    Query.SetField("lastonline", PlayerInfo["lbtl"]);
                    Query.SetField("mode0", PlayerInfo["mode0"]);
                    Query.SetField("mode1", PlayerInfo["mode1"]);
                    Query.SetField("mode2", PlayerInfo["mode2"]);
                    Query.Execute();

                    // Insert Army Data
                    Worker.ReportProgress(8, "Inserting Player Data Into Table: army");
                    Query = new InsertQueryBuilder("army", Driver);
                    Query.SetField("id", Pid);
                    for (int i = 0; i < 10; i++)
                    {
                        Query.SetField("time" + i, PlayerInfo["atm-" + i]);
                        Query.SetField("win" + i, PlayerInfo["awn-" + i]);
                        Query.SetField("loss" + i, PlayerInfo["alo-" + i]);
                        Query.SetField("best" + i, PlayerInfo["abr-" + i]);
                    }
                    Query.Execute();

                    // Insert Kit Data
                    Worker.ReportProgress(9, "Inserting Player Data Into Table: kits");
                    Query = new InsertQueryBuilder("kits", Driver);
                    Query.SetField("id", Pid);
                    for (int i = 0; i < 7; i++)
                    {
                        Query.SetField("time" + i, PlayerInfo["ktm-" + i]);
                        Query.SetField("kills" + i, PlayerInfo["kkl-" + i]);
                        Query.SetField("deaths" + i, PlayerInfo["kdt-" + i]);
                    }
                    Query.Execute();

                    // Insert Vehicle Data
                    Worker.ReportProgress(10, "Inserting Player Data Into Table: vehicles");
                    Query = new InsertQueryBuilder("vehicles", Driver);
                    Query.SetField("id", Pid);
                    Query.SetField("timepara", 0);
                    for (int i = 0; i < 7; i++)
                    {
                        Query.SetField("time" + i, PlayerInfo["vtm-" + i]);
                        Query.SetField("kills" + i, PlayerInfo["vkl-" + i]);
                        Query.SetField("deaths" + i, PlayerInfo["vdt-" + i]);
                        Query.SetField("rk" + i, PlayerInfo["vkr-" + i]);
                    }
                    Query.Execute();

                    // Insert Weapon Data
                    Worker.ReportProgress(11, "Inserting Player Data Into Table: weapons");
                    Query = new InsertQueryBuilder("weapons", Driver);
                    Query.SetField("id", Pid);
                    for (int i = 0; i < 9; i++)
                    {
                        Query.SetField("time" + i, PlayerInfo["wtm-" + i]);
                        Query.SetField("kills" + i, PlayerInfo["wkl-" + i]);
                        Query.SetField("deaths" + i, PlayerInfo["wdt-" + i]);
                    }

                    // Knife
                    Query.SetField("knifetime", PlayerInfo["wtm-9"]);
                    Query.SetField("knifekills", PlayerInfo["wkl-9"]);
                    Query.SetField("knifedeaths", PlayerInfo["wdt-9"]);
                    // Shockpad
                    Query.SetField("shockpadtime", PlayerInfo["wtm-10"]);
                    Query.SetField("shockpadkills", PlayerInfo["wkl-10"]);
                    Query.SetField("shockpaddeaths", PlayerInfo["wdt-10"]);
                    // Claymore
                    Query.SetField("claymoretime", PlayerInfo["wtm-11"]);
                    Query.SetField("claymorekills", PlayerInfo["wkl-11"]);
                    Query.SetField("claymoredeaths", PlayerInfo["wdt-11"]);
                    // Handgrenade
                    Query.SetField("handgrenadetime", PlayerInfo["wtm-12"]);
                    Query.SetField("handgrenadekills", PlayerInfo["wkl-12"]);
                    Query.SetField("handgrenadedeaths", PlayerInfo["wdt-12"]);
                    // SF Weapn Data
                    Query.SetField("tacticaldeployed", PlayerInfo["de-6"]);
                    Query.SetField("grapplinghookdeployed", PlayerInfo["de-7"]);
                    Query.SetField("ziplinedeployed", PlayerInfo["de-8"]);

                    Query.Execute();

                    // === Process Awards Data === //
                    Worker.ReportProgress(12, "Inserting Player Awards");
                    List<Dictionary<string, string>> Awards = StatsParser.ParseAwards(AwardLines);
                    foreach (Dictionary<string, string> Award in Awards)
                    {
                        Query = new InsertQueryBuilder("awards", Driver);
                        Query.SetField("id", Pid);
                        Query.SetField("awd", Award["id"]);
                        Query.SetField("level", Award["level"]);
                        Query.SetField("earned", Award["when"]);
                        Query.SetField("first", Award["first"]);
                        Query.Execute();
                    }

                    // === Process Map Data === //
                    Worker.ReportProgress(13, "Inserting Player Map Data");
                    PlayerInfo = StatsParser.ParseHeaderData(MapLines[3], MapLines[4]);
                    int[] Maps = new int[] {
                        0, 1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 105,
                        601, 300, 301, 302, 303, 304, 305, 306, 307,
                        10, 11, 110, 200, 201, 202, 12
                    };
                    foreach (int MapId in Maps)
                    {
                        if (PlayerInfo.ContainsKey("mtm-" + MapId))
                        {
                            Query = new InsertQueryBuilder("maps", Driver);
                            Query.SetField("id", Pid);
                            Query.SetField("mapid", MapId);
                            Query.SetField("time", PlayerInfo["mtm-" + MapId]);
                            Query.SetField("win", PlayerInfo["mwn-" + MapId]);
                            Query.SetField("loss", PlayerInfo["mls-" + MapId]);
                            Query.SetField("best", 0);
                            Query.SetField("worst", 0);
                            Query.Execute();
                        }
                    }

                    // Commit transaction
                    Transaction.Commit();
                }
                catch (Exception)
                {
                    Transaction.Rollback();
                    throw;
                }
                finally
                {
                    // Dispose dispose the transaction
                    Transaction.Dispose();
                }
            }
        }
Esempio n. 5
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;
                }
            }
        }
        /// <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();
            }
        }