/// <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(); } } }
/// <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(); } }