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