diff --git a/MHFZ_Overlay/Models/Structures/Enums.cs b/MHFZ_Overlay/Models/Structures/Enums.cs index 1d251be7..2e2d7bff 100644 --- a/MHFZ_Overlay/Models/Structures/Enums.cs +++ b/MHFZ_Overlay/Models/Structures/Enums.cs @@ -842,3 +842,32 @@ public enum DivaPrayerGemColor Green, Blue, } + +public enum GamePatch +{ + Vanilla, + Seph, + Ezemania, + Otyav1_1, + Tenrou, + Mezelounge, + /// + /// TODO + /// + Standard, +} + +public enum GamePatchLanguage +{ + JP, + EN, + FR, +} + +public enum GamePatchFile +{ + dat, + emd, + dll, + hddll, +} diff --git a/MHFZ_Overlay/Services/DatabaseService.cs b/MHFZ_Overlay/Services/DatabaseService.cs index 9b42999d..af02c9d9 100644 --- a/MHFZ_Overlay/Services/DatabaseService.cs +++ b/MHFZ_Overlay/Services/DatabaseService.cs @@ -941,19 +941,19 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { - var gameFolderPath = s.GameFolderPath; - var mhfdatHash = CalculateFileHash(gameFolderPath, @"\dat\mhfdat.bin"); - var mhfemdHash = CalculateFileHash(gameFolderPath, @"\dat\mhfemd.bin"); - var mhfinfHash = CalculateFileHash(gameFolderPath, @"\dat\mhfinf.bin"); - var mhfsqdHash = CalculateFileHash(gameFolderPath, @"\dat\mhfsqd.bin"); - var mhfodllHash = CalculateFileHash(gameFolderPath, @"\mhfo.dll"); - var mhfohddllHash = CalculateFileHash(gameFolderPath, @"\mhfo-hd.dll"); - var mhfexeHash = CalculateFileHash(gameFolderPath, @"\mhf.exe"); + var gameFolderPathStatus = s.GameFolderPath == @"C:\Program Files (x86)\CAPCOM\Monster Hunter Frontier Online" ? "Standard" : "Custom"; + var mhfdatHash = CalculateFileHash(s.GameFolderPath, @"\dat\mhfdat.bin"); + var mhfemdHash = CalculateFileHash(s.GameFolderPath, @"\dat\mhfemd.bin"); + var mhfinfHash = CalculateFileHash(s.GameFolderPath, @"\dat\mhfinf.bin"); + var mhfsqdHash = CalculateFileHash(s.GameFolderPath, @"\dat\mhfsqd.bin"); + var mhfodllHash = CalculateFileHash(s.GameFolderPath, @"\mhfo.dll"); + var mhfohddllHash = CalculateFileHash(s.GameFolderPath, @"\mhfo-hd.dll"); + var mhfexeHash = CalculateFileHash(s.GameFolderPath, @"\mhf.exe"); var gameFolderData = string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}", createdAt, createdBy, runID, - gameFolderPath, mhfdatHash, mhfemdHash, + gameFolderPathStatus, mhfdatHash, mhfemdHash, mhfinfHash, mhfsqdHash, mhfodllHash, mhfohddllHash, mhfexeHash); var gameFolderHash = CalculateStringHash(gameFolderData); @@ -962,7 +962,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@CreatedAt", createdAt); cmd.Parameters.AddWithValue("@CreatedBy", createdBy); cmd.Parameters.AddWithValue("@RunID", runID); - cmd.Parameters.AddWithValue("@GameFolderPath", gameFolderPath); + cmd.Parameters.AddWithValue("@GameFolderPath", gameFolderPathStatus); cmd.Parameters.AddWithValue("@mhfdatHash", mhfdatHash); cmd.Parameters.AddWithValue("@mhfemdHash", mhfemdHash); cmd.Parameters.AddWithValue("@mhfinfHash", mhfinfHash); @@ -3151,6 +3151,26 @@ AFTER DELETE ON QuestsQuestVariant cmd.ExecuteNonQuery(); } + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_game_patch_updates + AFTER UPDATE ON QuestsGamePatch + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_game_patch_deletion + AFTER DELETE ON QuestsGamePatch + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } + using (var cmd = new SQLiteCommand(conn)) { cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_bingo_updates @@ -6174,6 +6194,20 @@ FOREIGN KEY(RunID) REFERENCES Quests(RunID) cmd.ExecuteNonQuery(); } + sql = @"CREATE TABLE IF NOT EXISTS QuestsGamePatch( + QuestsGamePatchID INTEGER PRIMARY KEY AUTOINCREMENT, + mhfdatInfo TEXT NOT NULL DEFAULT '', + mhfemdInfo TEXT NOT NULL DEFAULT '', + mhfodllInfo TEXT NOT NULL DEFAULT '', + mhfohddllInfo TEXT NOT NULL DEFAULT '', + RunID INTEGER NOT NULL, + FOREIGN KEY(RunID) REFERENCES Quests(RunID) + )"; + using (var cmd = new SQLiteCommand(sql, conn)) + { + cmd.ExecuteNonQuery(); + } + // a mh game but like a MUD. hunt in-game to get many kinds of points for this game. hunt and tame monsters. challenge other CPU players/monsters. sql = @"CREATE TABLE IF NOT EXISTS GachaMaterial( GachaMaterialID INTEGER PRIMARY KEY, @@ -17732,6 +17766,167 @@ private void PerformUpdateToVersion_0_37_0(SQLiteConnection connection, DataLoad UpdateQuestsObjectiveImage(connection); UpdateQuestsMonsterDictionaries(connection, dataLoader); + FillQuestsGamePatch(connection, dataLoader); + + // for privacy + ChangeGameFolderPath(connection); + } + + private void ChangeGameFolderPath(SQLiteConnection conn) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot change game folder path. dataSource: {0}", this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd0 = new SQLiteCommand(conn)) + { + cmd0.CommandText = @"DROP TRIGGER IF EXISTS prevent_game_folder_updates"; + cmd0.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = "SELECT * FROM GameFolder"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var path = reader["GameFolderPath"]?.ToString() ?? string.Empty; + var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + + if (path == string.Empty || path == null || runID == 0) + { + continue; + } + + var newPath = path == @"C:\Program Files (x86)\CAPCOM\Monster Hunter Frontier Online" ? "Standard" : "Custom"; + + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = + @"UPDATE GameFolder SET GameFolderPath = @GameFolderPath WHERE RunID = @RunID"; + cmd2.Parameters.AddWithValue("@RunID", runID); + cmd2.Parameters.AddWithValue("@GameFolderPath", newPath); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + using (var cmd1 = new SQLiteCommand(conn)) + { + cmd1.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_game_folder_updates + AFTER UPDATE ON GameFolder + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd1.ExecuteNonQuery(); + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug("Changed game folder paths in GameFolder table"); + } + + private void FillQuestsGamePatch(SQLiteConnection conn, DataLoader dataLoader) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot fill game patch. dataSource: {0}", this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd0 = new SQLiteCommand(conn)) + { + cmd0.CommandText = @"DROP TRIGGER IF EXISTS prevent_quests_game_patch_updates"; + cmd0.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = "SELECT * FROM GameFolder"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + var dat = reader["mhfdatHash"]?.ToString() ?? "0"; + var emd = reader["mhfemdHash"]?.ToString() ?? "0"; + var mhfodll = reader["mhfodllHash"]?.ToString() ?? "0"; + var mhfohddll = reader["mhfohddllHash"]?.ToString() ?? "0"; + + if (runID == 0) + { + continue; + } + + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = + @"INSERT INTO + QuestsGamePatch(RunID, mhfdatInfo, mhfemdInfo, mhfodllInfo, mhfohddllInfo) + VALUES + ( + @RunID, + @mhfdatInfo, + @mhfemdInfo, + @mhfodllInfo, + @mhfohddllInfo + )"; + cmd2.Parameters.AddWithValue("@RunID", runID); + cmd2.Parameters.AddWithValue("@mhfdatInfo", dataLoader.Model.GetGamePatchInfo(GamePatchFile.dat, dat)); + cmd2.Parameters.AddWithValue("@mhfemdInfo", dataLoader.Model.GetGamePatchInfo(GamePatchFile.emd, emd)); + cmd2.Parameters.AddWithValue("@mhfodllInfo", dataLoader.Model.GetGamePatchInfo(GamePatchFile.dll, mhfodll)); + cmd2.Parameters.AddWithValue("@mhfohddllInfo", dataLoader.Model.GetGamePatchInfo(GamePatchFile.hddll, mhfohddll)); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + using (var cmd1 = new SQLiteCommand(conn)) + { + cmd1.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_game_patch_updates + AFTER UPDATE ON QuestsGamePatch + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd1.ExecuteNonQuery(); + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug("Filled game patches values in table"); } /// diff --git a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs index 98becfed..c185e5a3 100644 --- a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs +++ b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs @@ -1956,6 +1956,48 @@ public bool GetNotRoad() return this.IsNotRoad(); } + public string GetGamePatchInfo(GamePatchFile file, string hash) + { + var result = "Unknown"; + + switch (file) + { + case GamePatchFile.dat: + QuestsGamePatches.datHashInfo.TryGetValue(hash, out var datInfo); + if (datInfo != null) + { + var a = datInfo.Keys.FirstOrDefault(); + var b = datInfo.Keys.FirstOrDefault().ToString(); + + return $"{datInfo.Keys.FirstOrDefault().ToString()}-{datInfo.Values.FirstOrDefault().ToString()}"; + } + break; + case GamePatchFile.emd: + QuestsGamePatches.datHashInfo.TryGetValue(hash, out var emdInfo); + if (emdInfo != null) + { + return $"{emdInfo.Keys.FirstOrDefault().ToString()}-{emdInfo.Values.FirstOrDefault().ToString()}"; + } + break; + case GamePatchFile.dll: + QuestsGamePatches.datHashInfo.TryGetValue(hash, out var dllInfo); + if (dllInfo != null) + { + return $"{dllInfo.Keys.FirstOrDefault().ToString()}-{dllInfo.Values.FirstOrDefault().ToString()}"; + } + break; + case GamePatchFile.hddll: + QuestsGamePatches.datHashInfo.TryGetValue(hash, out var hddllInfo); + if (hddllInfo != null) + { + return $"{hddllInfo.Keys.FirstOrDefault().ToString()}-{hddllInfo.Values.FirstOrDefault().ToString()}"; + } + break; + } + + return result; + } + // assumption: it follows ferias' monster part order top to bottom, presumably (e.g. head is at the top, so part 0 is head, and so on) // grouping by skeleton too