diff --git a/CHANGELOG.md b/CHANGELOG.md
index bb1423e8..2e8d5b4c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,27 @@
+## [0.41.0](https://github.com/DorielRivalet/MHFZ_Overlay/compare/v0.40.0...v0.41.0) (2024-10-27)
+
+
+### Features
+
+* add hotkeys window ([d25af92](https://github.com/DorielRivalet/MHFZ_Overlay/commit/d25af927216c2561efe8ff352f26d4234d720eb7)), closes [#375](https://github.com/DorielRivalet/MHFZ_Overlay/issues/375)
+* **database:** add party size dictionary ([20f34ab](https://github.com/DorielRivalet/MHFZ_Overlay/commit/20f34abd3d9f8d7d8b939a91a950d3170f198aa1)), closes [#388](https://github.com/DorielRivalet/MHFZ_Overlay/issues/388)
+* **database:** reduce database size ([e30aacd](https://github.com/DorielRivalet/MHFZ_Overlay/commit/e30aacdcf5d9d4df46c78ab98dee54ba33cb3614)), closes [#389](https://github.com/DorielRivalet/MHFZ_Overlay/issues/389)
+* update monster images ([ed67b0e](https://github.com/DorielRivalet/MHFZ_Overlay/commit/ed67b0ea0146d468e02f9372671524e95ff3a33f))
+
+
+### Bug Fixes
+
+* **achievement:** fix ds achievements ([eb66abe](https://github.com/DorielRivalet/MHFZ_Overlay/commit/eb66abe45ae18ce93a1572fbe2bb2efdf89742d6)), closes [#390](https://github.com/DorielRivalet/MHFZ_Overlay/issues/390)
+
+
+### For Developers
+
+* bump version ([5c670a2](https://github.com/DorielRivalet/MHFZ_Overlay/commit/5c670a2f211656d8038200d26161034213be09ee))
+* **deps:** bump braces from 3.0.2 to 3.0.3 ([1c1bf79](https://github.com/DorielRivalet/MHFZ_Overlay/commit/1c1bf7994fafd172d208fb0525c8318f0e143fc3))
+* update README.md ([31b1db2](https://github.com/DorielRivalet/MHFZ_Overlay/commit/31b1db2299781a523c7ecac56866a6ef1a0afa2b))
+
## [0.40.0](https://github.com/DorielRivalet/MHFZ_Overlay/compare/v0.39.1...v0.40.0) (2024-06-19)
diff --git a/MHFZ_Overlay/App.config b/MHFZ_Overlay/App.config
index 51b382b6..76e0a0c0 100644
--- a/MHFZ_Overlay/App.config
+++ b/MHFZ_Overlay/App.config
@@ -1044,6 +1044,15 @@
True
+
+ Shift + F1
+
+
+ Shift + F5
+
+
+ Shift + F6
+
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.png b/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.png
index bf4293f2..6d402a51 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.png and b/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.webp b/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.webp
new file mode 100644
index 00000000..f4764c5f
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/azure_rathalos.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.png b/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.png
index 842e8ea5..f8d65500 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.png and b/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.webp b/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.webp
new file mode 100644
index 00000000..13840efd
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/conquest_shantien.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.png b/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.png
index 8b9fb4f1..a3c9f6c8 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.png and b/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.webp b/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.webp
new file mode 100644
index 00000000..87bbe3d3
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/disufiroa.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.png b/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.png
index c0e9a9e4..3a295066 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.png and b/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.webp b/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.webp
new file mode 100644
index 00000000..87e67912
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/gold_rathian.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.png b/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.png
index d6943ebe..2c6ca688 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.png and b/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.webp b/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.webp
new file mode 100644
index 00000000..082ef167
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/pink_rathian.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.png b/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.png
index e3b1bb02..baa4cf39 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.png and b/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.webp b/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.webp
new file mode 100644
index 00000000..9fc2a520
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/rathalos.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/rathian.png b/MHFZ_Overlay/Assets/Icons/png/monster/rathian.png
index 3abb2cf6..1922e43e 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/rathian.png and b/MHFZ_Overlay/Assets/Icons/png/monster/rathian.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/rathian.webp b/MHFZ_Overlay/Assets/Icons/png/monster/rathian.webp
new file mode 100644
index 00000000..644c56e9
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/rathian.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shantien.png b/MHFZ_Overlay/Assets/Icons/png/monster/shantien.png
index 70504cfd..57e9b072 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/shantien.png and b/MHFZ_Overlay/Assets/Icons/png/monster/shantien.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shantien.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shantien.webp
new file mode 100644
index 00000000..afcfbc55
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shantien.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.png
index bc8650a7..9f68a205 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.png and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.webp
new file mode 100644
index 00000000..19c055f5
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_disufiroa.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.gif b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.gif
new file mode 100644
index 00000000..482eb985
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.gif differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.png
index 2ab2da42..7c919ef3 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.png and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.webp
new file mode 100644
index 00000000..e4c140ef
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.png
new file mode 100644
index 00000000..0594fd6f
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.webp
new file mode 100644
index 00000000..d33df936
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase2.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.png
new file mode 100644
index 00000000..730abe64
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.webp
new file mode 100644
index 00000000..17c23a06
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase3.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.png
new file mode 100644
index 00000000..1eb716b0
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.webp
new file mode 100644
index 00000000..6ccdf93c
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase4.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.png
new file mode 100644
index 00000000..da26ddd5
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.webp
new file mode 100644
index 00000000..f89d07e9
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase5.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.png
new file mode 100644
index 00000000..471c846f
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.webp
new file mode 100644
index 00000000..3a47bbd6
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase6.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.png
new file mode 100644
index 00000000..59409905
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.webp
new file mode 100644
index 00000000..f3662259
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase7.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.png b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.png
new file mode 100644
index 00000000..21442b3f
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.webp b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.webp
new file mode 100644
index 00000000..f7bd6f5d
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/shiten_unknown_phase8.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.png b/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.png
index a43afd33..c096936e 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.png and b/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.webp b/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.webp
new file mode 100644
index 00000000..545b7aaf
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/silver_rathalos.webp differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/unknown.png b/MHFZ_Overlay/Assets/Icons/png/monster/unknown.png
index 76267bfc..0467c9a3 100644
Binary files a/MHFZ_Overlay/Assets/Icons/png/monster/unknown.png and b/MHFZ_Overlay/Assets/Icons/png/monster/unknown.png differ
diff --git a/MHFZ_Overlay/Assets/Icons/png/monster/unknown.webp b/MHFZ_Overlay/Assets/Icons/png/monster/unknown.webp
new file mode 100644
index 00000000..99ab3763
Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/monster/unknown.webp differ
diff --git a/MHFZ_Overlay/MHFZ_Overlay.csproj b/MHFZ_Overlay/MHFZ_Overlay.csproj
index 3fb4ff83..a759e1dc 100644
--- a/MHFZ_Overlay/MHFZ_Overlay.csproj
+++ b/MHFZ_Overlay/MHFZ_Overlay.csproj
@@ -21,7 +21,7 @@
MHFZ Overlay
Doriel Rivalet
Doriel Rivalet
- 0.40.0
+ 0.41.0
https://github.com/DorielRivalet/mhfz-overlay
https://github.com/DorielRivalet/mhfz-overlay.git
git
@@ -2001,44 +2001,44 @@
-
+
-
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
+
+
+
+
+
+
-
+
diff --git a/MHFZ_Overlay/Models/Collections/Achievements.cs b/MHFZ_Overlay/Models/Collections/Achievements.cs
index 3fe09973..09d7baa3 100644
--- a/MHFZ_Overlay/Models/Collections/Achievements.cs
+++ b/MHFZ_Overlay/Models/Collections/Achievements.cs
@@ -6260,7 +6260,7 @@ [] [U] [] [] []
Description = string.Empty,
Rank = AchievementRank.Platinum,
Image = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/weapon/Dual_Blades_Icon_White.png",
- Objective = "Defeat Lv9999 Conquest Shantien solo with Dual Swords without dropping the combo (maximum sharpening buff, Speedrun mode).",
+ Objective = "Defeat Lv9999 Conquest Shantien solo with Dual Swords without dropping the combo more than 3 times (maximum sharpening buff, Speedrun mode).",
IsSecret = false,
Hint = string.Empty,
}
@@ -6286,7 +6286,7 @@ [] [U] [] [] []
Description = string.Empty,
Rank = AchievementRank.Platinum,
Image = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/weapon/Dual_Blades_Icon_White.png",
- Objective = "Defeat Upper Shiten Disufiroa solo with Dual Swords without dropping the combo (maximum sharpening buff, Speedrun mode).",
+ Objective = "Defeat Upper Shiten Disufiroa solo with Dual Swords without dropping the combo more than 3 times (maximum sharpening buff, Speedrun mode).",
IsSecret = false,
Hint = string.Empty,
}
diff --git a/MHFZ_Overlay/Models/Quest.cs b/MHFZ_Overlay/Models/Quest.cs
index 5cca939f..c993c315 100644
--- a/MHFZ_Overlay/Models/Quest.cs
+++ b/MHFZ_Overlay/Models/Quest.cs
@@ -5,6 +5,7 @@
namespace MHFZ_Overlay.Models;
using System;
+using System.Collections.Generic;
// TODO: ORM
// get the graphs from here
@@ -86,4 +87,6 @@ public sealed class Quest
public long? PartySize { get; set; } = 0;
+ public string? PartySizeDictionary { get; set; } = string.Empty;
+
}
diff --git a/MHFZ_Overlay/Services/AchievementService.cs b/MHFZ_Overlay/Services/AchievementService.cs
index 2dcb8c76..e26538ec 100644
--- a/MHFZ_Overlay/Services/AchievementService.cs
+++ b/MHFZ_Overlay/Services/AchievementService.cs
@@ -3111,7 +3111,7 @@ join styleRankSkills in databaseManagerInstance.AllStyleRankSkills on quest.RunI
return false;
}
- if (databaseManagerInstance.AllQuestsWeaponBuffs.Any(q => q.RunID == foundConquestShantienQuest.First().RunID && q.DualSwordsSharpensDictionary.Count == 4 && q.DualSwordsSharpensDictionary.Count((e) => e.Value == 0) == 0))
+ if (databaseManagerInstance.AllQuestsWeaponBuffs.Any(q => q.RunID == foundConquestShantienQuest.First().RunID && q.DualSwordsSharpensDictionary.Count >= 4 && q.DualSwordsSharpensDictionary.Count((e) => e.Value == 0) <= 3))
{
return true;
}
@@ -3151,7 +3151,7 @@ join styleRankSkills in databaseManagerInstance.AllStyleRankSkills on quest.RunI
return false;
}
- if (databaseManagerInstance.AllQuestsWeaponBuffs.Any(q => q.RunID == foundUpperShitenDisufiroaQuest.First().RunID && q.DualSwordsSharpensDictionary.Count == 4 && q.DualSwordsSharpensDictionary.Count((e) => e.Value == 0) == 0))
+ if (databaseManagerInstance.AllQuestsWeaponBuffs.Any(q => q.RunID == foundUpperShitenDisufiroaQuest.First().RunID && q.DualSwordsSharpensDictionary.Count >= 4 && q.DualSwordsSharpensDictionary.Count((e) => e.Value == 0) <= 3))
{
return true;
}
diff --git a/MHFZ_Overlay/Services/DatabaseService.cs b/MHFZ_Overlay/Services/DatabaseService.cs
index 60b4ddaa..9bcad479 100644
--- a/MHFZ_Overlay/Services/DatabaseService.cs
+++ b/MHFZ_Overlay/Services/DatabaseService.cs
@@ -148,9 +148,9 @@ public void CheckIfUserSetDatabasePath()
{
var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
- if (string.IsNullOrEmpty(s.DatabaseFilePath) || !Directory.Exists(Path.GetDirectoryName(s.DatabaseFilePath)))
+ if (string.IsNullOrEmpty(s.DatabaseFilePath) || !Directory.Exists(System.IO.Path.GetDirectoryName(s.DatabaseFilePath)))
{
- this.connectionString = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\MHFZ_Overlay.sqlite");
+ this.connectionString = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\MHFZ_Overlay.sqlite");
// Show warning to user that they should set a custom database path to prevent data loss on update
Logger.Warn(CultureInfo.InvariantCulture, "The database file is being saved to the overlay default location");
@@ -325,6 +325,7 @@ public bool SetupLocalDatabase(DataLoader dataLoader)
this.CreateDatabaseIndexes(conn);
this.CreateDatabaseTriggers(conn);
this.CheckDatabaseVersion(conn, dataLoader);
+ this.VacuumDatabaseFile(conn);
// TODO: avoid using version files. find alternatives to IO.
WriteNewVersionToFile();
@@ -334,7 +335,7 @@ public bool SetupLocalDatabase(DataLoader dataLoader)
{
conn.Open();
- var referenceSchemaFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
+ var referenceSchemaFilePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
var doesReferenceSchemaFileExist = FileService.CheckIfFileExists(referenceSchemaFilePath, "Checking reference schema");
@@ -518,7 +519,7 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
var createdAt = DateTime.UtcNow;
var createdBy = ViewModels.Windows.AddressModel.GetFullCurrentProgramVersion();
var playerID = 1;
- var partySize = dataLoader.Model.PartySize();
+ var partySize = dataLoader.Model.PartySizeDictionary.FirstOrDefault().Value;
using (var transaction = conn.BeginTransaction())
{
@@ -588,7 +589,8 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
Monster1PartThresholdDictionary,
Monster2PartThresholdDictionary,
IsHighGradeEdition,
- RefreshRate
+ RefreshRate,
+ PartySizeDictionary
) VALUES (
@QuestHash,
@CreatedAt,
@@ -638,7 +640,8 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
@Monster1PartThresholdDictionary,
@Monster2PartThresholdDictionary,
@IsHighGradeEdition,
- @RefreshRate
+ @RefreshRate,
+ @PartySizeDictionary
)";
using (var cmd = new SQLiteCommand(sql, conn))
@@ -755,9 +758,16 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
var isHighGradeEdition = dataLoader.IsHighGradeEdition ? 1 : 0;
var refreshRate = s.RefreshRate;
+ var partySizeDictionary = dataLoader.Model.PartySizeDictionary;
+ hitsTakenBlockedPerSecondDictionary = TimeService.FilterFramesBySecond(hitsTakenBlockedPerSecondDictionary);
+ damagePerSecondDictionary = TimeService.FilterFramesBySecond(damagePerSecondDictionary);
+ hitsPerSecondDictionary = TimeService.FilterFramesBySecond(hitsPerSecondDictionary);
+ actionsPerMinuteDictionary = TimeService.FilterFramesBySecond(actionsPerMinuteDictionary);
+
+ // NOTE: 2024-10-22 v0.41 filtered certain fields to save space.
var questData = string.Format(CultureInfo.InvariantCulture,
- "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}{17}{18}{19}{20}{21}{22}{23}{24}{25}{26}{27}{28}{29}{30}{31}{32}{33}{34}{35}{36}{37}{38}{39}{40}{41}{42}{43}{44}{45}{46}{47}",
+ "{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}{17}{18}{19}{20}{21}{22}{23}{24}{25}{26}{27}{28}{29}{30}{31}{32}{33}{34}{35}{36}{37}{38}{39}{40}{41}{42}{43}{44}{45}{46}{47}{48}",
runID, createdAt, createdBy, questID, timeLeft,
finalTimeValue, finalTimeDisplay, objectiveImage, objectiveTypeID, objectiveQuantity,
starGrade, rankName, objectiveName, date, attackBuffDictionary,
@@ -767,7 +777,7 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
actualOverlayMode, partySize, monster1HPDictionary, monster2HPDictionary, monster3HPDictionary,
monster4HPDictionary, monster1AttackMultiplierDictionary, monster1DefenseRateDictionary, monster1SizeMultiplierDictionary, monster1PoisonThresholdDictionary,
monster1SleepThresholdDictionary, monster1ParalysisThresholdDictionary, monster1BlastThresholdDictionary, monster1StunThresholdDictionary, monster1PartThresholdDictionary,
- monster2PartThresholdDictionary, isHighGradeEdition, refreshRate);
+ monster2PartThresholdDictionary, isHighGradeEdition, refreshRate, partySizeDictionary);
// Calculate the hash value for the data in the row
var questHash = CalculateStringHash(questData); // concatenate the relevant data from the row
@@ -821,6 +831,7 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest,
cmd.Parameters.AddWithValue("@Monster2PartThresholdDictionary", JsonConvert.SerializeObject(monster2PartThresholdDictionary));
cmd.Parameters.AddWithValue("@IsHighGradeEdition", isHighGradeEdition);
cmd.Parameters.AddWithValue("@RefreshRate", refreshRate);
+ cmd.Parameters.AddWithValue("@PartySizeDictionary", JsonConvert.SerializeObject(partySizeDictionary));
cmd.ExecuteNonQuery();
}
@@ -3866,7 +3877,7 @@ public string GetOverlayHash()
// Find the path of the first found process with the name "MHFZ_Overlay.exe"
var exeName = "MHFZ_Overlay.exe";
- var processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(exeName));
+ var processes = Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(exeName));
var exePath = string.Empty;
if (processes.Length > 0)
{
@@ -3882,7 +3893,7 @@ public string GetOverlayHash()
}
else
{
- exePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, exeName);
+ exePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, exeName);
}
if (exePath == null)
@@ -3919,7 +3930,7 @@ public string StoreOverlayHash()
// Find the path of the first found process with the name "MHFZ_Overlay.exe"
var exeName = "MHFZ_Overlay.exe";
- var processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(exeName));
+ var processes = Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(exeName));
var exePath = string.Empty;
if (processes.Length > 0)
{
@@ -3935,7 +3946,7 @@ public string StoreOverlayHash()
}
else
{
- exePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, exeName);
+ exePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, exeName);
}
if (exePath == null)
@@ -4419,7 +4430,7 @@ private Dictionary> CreateReferenceSchemaJSON
{
// Serialize the schema dictionary to a JSON string
var json = JsonConvert.SerializeObject(schema, Formatting.Indented);
- var referenceSchemaFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
+ var referenceSchemaFilePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
// Write the JSON string to the reference schema file
FileService.WriteToFile(referenceSchemaFilePath, json);
@@ -4464,7 +4475,7 @@ private void RecreateReferenceSchemaFile()
Restarting overlay after deleting the file.",
Messages.InfoTitle, MessageBoxButton.OK, MessageBoxImage.Information);
- var referenceSchemaFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
+ var referenceSchemaFilePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
var databaseFolder = this.GetDatabaseFolderPath();
if (string.IsNullOrEmpty(databaseFolder))
@@ -4474,7 +4485,7 @@ private void RecreateReferenceSchemaFile()
}
// Create the backups folder if it does not exist
- var backupsFolderPath = Path.Combine(databaseFolder, BackupFolderName);
+ var backupsFolderPath = System.IO.Path.Combine(databaseFolder, BackupFolderName);
if (!Directory.Exists(backupsFolderPath))
{
Directory.CreateDirectory(backupsFolderPath);
@@ -4485,7 +4496,7 @@ private void RecreateReferenceSchemaFile()
var backupFileName = $"reference_schema_backup_{timestamp}.json";
// Create the full path for the backup file
- var backupFilePath = Path.Combine(backupsFolderPath, backupFileName);
+ var backupFilePath = System.IO.Path.Combine(backupsFolderPath, backupFileName);
Logger.Info(CultureInfo.InvariantCulture, "Making reference schema backup. Reference schema file path: {0}. Backup file path: {1}", referenceSchemaFilePath, backupFilePath);
FileService.CopyFileToDestination(referenceSchemaFilePath, backupFilePath);
FileService.DeleteFile(referenceSchemaFilePath);
@@ -5012,6 +5023,7 @@ ObjectiveTypeID INTEGER NOT NULL CHECK (ObjectiveTypeID >= 0) DEFAULT 0,
Monster2PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
IsHighGradeEdition INTEGER NOT NULL CHECK (IsHighGradeEdition IN (0, 1)) DEFAULT 0,
RefreshRate INTEGER NOT NULL CHECK (RefreshRate >= 1 AND RefreshRate <= 30) DEFAULT 30,
+ PartySizeDictionary TEXT NOT NULL DEFAULT '{}',
FOREIGN KEY(ObjectiveTypeID) REFERENCES ObjectiveType(ObjectiveTypeID)
-- FOREIGN KEY(RankNameID) REFERENCES RankName(RankNameID)
)";
@@ -16754,9 +16766,16 @@ private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion,
case 5: // 0.37.1
{
this.PerformUpdateToVersion_0_37_1(conn, dataLoader);
- this.EnforceForeignKeys(conn);
newVersion++;
Logger.Info(CultureInfo.InvariantCulture, "Updated schema to version v0.37.1. newVersion {0}", newVersion);
+ goto case 6;
+ }
+ case 6: // 0.41.0
+ {
+ this.PerformUpdateToVersion_0_41_0(conn, dataLoader);
+ this.EnforceForeignKeys(conn);
+ newVersion++;
+ Logger.Info(CultureInfo.InvariantCulture, "Updated schema to version v0.41.0. newVersion {0}", newVersion);
break;
}
// case 2://v0.24.0
@@ -16788,7 +16807,6 @@ private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion,
// 12. If foreign keys constraints were originally enabled, re-enable them now.
EnableForeignKeyConstraints(conn);
-
// [self endTransaction];
// Stop the stopwatch
stopwatch.Stop();
@@ -17024,7 +17042,7 @@ private void UpdateDatabaseSchema(SQLiteConnection connection, DataLoader dataLo
}
this.MigrateToSchemaFromVersion(connection, currentUserVersion, dataLoader);
- var referenceSchemaFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
+ var referenceSchemaFilePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json");
FileService.DeleteFile(referenceSchemaFilePath);
// later on it creates it
@@ -17389,6 +17407,8 @@ v0.24 to v0.25 (fixing the refreshrate check is above, but the fix is implemente
Monster1PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
Monster2PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+
+ v0.41 adds PartySizeDictionary
*/
using (var updateCommand = new SQLiteCommand(updateQuery, connection))
@@ -17939,6 +17959,7 @@ ObjectiveTypeID INTEGER NOT NULL CHECK (ObjectiveTypeID >= 0) DEFAULT 0,
Monster2PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
IsHighGradeEdition INTEGER NOT NULL CHECK (IsHighGradeEdition IN (0, 1)) DEFAULT 0,
RefreshRate INTEGER NOT NULL CHECK (RefreshRate >= 1 AND RefreshRate <= 30) DEFAULT 30,
+ PartySizeDictionary TEXT NOT NULL DEFAULT '{}',
FOREIGN KEY(ObjectiveTypeID) REFERENCES ObjectiveType(ObjectiveTypeID)
-- FOREIGN KEY(RankNameID) REFERENCES RankName(RankNameID)
)";
@@ -17997,7 +18018,8 @@ UPDATE new_Quests
Monster1PartThresholdDictionary = (SELECT Monster1PartThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
Monster2PartThresholdDictionary = (SELECT Monster2PartThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
IsHighGradeEdition = (SELECT IsHighGradeEdition FROM Quests WHERE Quests.RunID = new_Quests.RunID),
- RefreshRate = (SELECT RefreshRate FROM Quests WHERE Quests.RunID = new_Quests.RunID)
+ RefreshRate = (SELECT RefreshRate FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ PartySizeDictionary = (SELECT PartySizeDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID)
WHERE EXISTS (SELECT 1 FROM Quests WHERE Quests.RunID = new_Quests.RunID)"
;
@@ -18210,6 +18232,275 @@ private void PerformUpdateToVersion_0_37_1(SQLiteConnection connection, DataLoad
FillQuestsGamePatch(connection, dataLoader);
}
+ private void PerformUpdateToVersion_0_41_0(SQLiteConnection connection, DataLoader dataLoader)
+ {
+ UpdateQuestsDictionariesToFiltered(connection, dataLoader);
+ UpdateTableQuests_0_41_0(connection);
+ }
+
+ private void UpdateTableQuests_0_41_0(SQLiteConnection connection)
+ {
+ var sql = @"CREATE TABLE IF NOT EXISTS new_Quests
+ (
+ QuestHash TEXT NOT NULL DEFAULT '',
+ CreatedAt TEXT NOT NULL DEFAULT '',
+ CreatedBy TEXT NOT NULL DEFAULT '',
+ RunID INTEGER PRIMARY KEY AUTOINCREMENT,
+ QuestID INTEGER NOT NULL CHECK (QuestID >= 0) DEFAULT 0,
+ TimeLeft INTEGER NOT NULL DEFAULT 0,
+ FinalTimeValue INTEGER NOT NULL DEFAULT 0,
+ FinalTimeDisplay TEXT NOT NULL DEFAULT '',
+ ObjectiveImage TEXT NOT NULL DEFAULT '',
+ ObjectiveTypeID INTEGER NOT NULL CHECK (ObjectiveTypeID >= 0) DEFAULT 0,
+ ObjectiveQuantity INTEGER NOT NULL DEFAULT 0,
+ StarGrade INTEGER NOT NULL DEFAULT 0,
+ RankName TEXT NOT NULL DEFAULT '',
+ ObjectiveName TEXT NOT NULL DEFAULT '',
+ Date TEXT NOT NULL DEFAULT '',
+ YouTubeID TEXT DEFAULT 'dQw4w9WgXcQ', -- default value for YouTubeID is a Rick Roll video
+ -- DpsData TEXT NOT NULL DEFAULT '',
+ AttackBuffDictionary TEXT NOT NULL DEFAULT '{}',
+ HitCountDictionary TEXT NOT NULL DEFAULT '{}',
+ HitsPerSecondDictionary TEXT NOT NULL DEFAULT '{}',
+ DamageDealtDictionary TEXT NOT NULL DEFAULT '{}',
+ DamagePerSecondDictionary TEXT NOT NULL DEFAULT '{}',
+ AreaChangesDictionary TEXT NOT NULL DEFAULT '{}',
+ CartsDictionary TEXT NOT NULL DEFAULT '{}',
+ HitsTakenBlockedDictionary TEXT NOT NULL DEFAULT '{}',
+ HitsTakenBlockedPerSecondDictionary TEXT NOT NULL DEFAULT '{}',
+ PlayerHPDictionary TEXT NOT NULL DEFAULT '{}',
+ PlayerStaminaDictionary TEXT NOT NULL DEFAULT '{}',
+ KeystrokesDictionary TEXT NOT NULL DEFAULT '{}',
+ MouseInputDictionary TEXT NOT NULL DEFAULT '{}',
+ GamepadInputDictionary TEXT NOT NULL DEFAULT '{}',
+ ActionsPerMinuteDictionary TEXT NOT NULL DEFAULT '{}',
+ OverlayModeDictionary TEXT NOT NULL DEFAULT '{}',
+ ActualOverlayMode TEXT NOT NULL DEFAULT 'Standard',
+ PartySize INTEGER NOT NULL DEFAULT 0,
+ Monster1HPDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster2HPDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster3HPDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster4HPDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1AttackMultiplierDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1DefenseRateDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1SizeMultiplierDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1PoisonThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1SleepThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1ParalysisThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1BlastThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1StunThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster1PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ Monster2PartThresholdDictionary TEXT NOT NULL DEFAULT '{}',
+ IsHighGradeEdition INTEGER NOT NULL CHECK (IsHighGradeEdition IN (0, 1)) DEFAULT 0,
+ RefreshRate INTEGER NOT NULL CHECK (RefreshRate >= 1 AND RefreshRate <= 30) DEFAULT 30,
+ PartySizeDictionary TEXT NOT NULL DEFAULT '{}',
+ FOREIGN KEY(ObjectiveTypeID) REFERENCES ObjectiveType(ObjectiveTypeID)
+ -- FOREIGN KEY(RankNameID) REFERENCES RankName(RankNameID)
+ )";
+ using (var cmd = new SQLiteCommand(sql, connection))
+ {
+ cmd.ExecuteNonQuery();
+ }
+
+ var updateQuery = @"
+ UPDATE new_Quests
+ SET QuestHash = (SELECT QuestHash FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ CreatedAt = (SELECT CreatedAt FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ CreatedBy = (SELECT CreatedBy FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ QuestID = (SELECT QuestID FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ TimeLeft = (SELECT TimeLeft FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ FinalTimeValue = (SELECT FinalTimeValue FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ FinalTimeDisplay = (SELECT FinalTimeDisplay FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ObjectiveImage = (SELECT ObjectiveImage FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ObjectiveTypeID = (SELECT ObjectiveTypeID FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ObjectiveQuantity = (SELECT ObjectiveQuantity FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ StarGrade = (SELECT StarGrade FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ RankName = (SELECT RankName FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ObjectiveName = (SELECT ObjectiveName FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Date = (SELECT Date FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ YouTubeID = (SELECT YouTubeID FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ AttackBuffDictionary = (SELECT AttackBuffDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ HitCountDictionary = (SELECT HitCountDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ HitsPerSecondDictionary = (SELECT HitsPerSecondDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ DamageDealtDictionary = (SELECT DamageDealtDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ DamagePerSecondDictionary = (SELECT DamagePerSecondDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ AreaChangesDictionary = (SELECT AreaChangesDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ CartsDictionary = (SELECT CartsDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ HitsTakenBlockedDictionary = (SELECT HitsTakenBlockedDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ HitsTakenBlockedPerSecondDictionary = (SELECT HitsTakenBlockedPerSecondDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ PlayerHPDictionary = (SELECT PlayerHPDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ PlayerStaminaDictionary = (SELECT PlayerStaminaDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ KeystrokesDictionary = (SELECT KeystrokesDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ MouseInputDictionary = (SELECT MouseInputDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ GamepadInputDictionary = (SELECT GamepadInputDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ActionsPerMinuteDictionary = (SELECT ActionsPerMinuteDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ OverlayModeDictionary = (SELECT OverlayModeDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ ActualOverlayMode = (SELECT ActualOverlayMode FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ PartySize = (SELECT PartySize FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1HPDictionary = (SELECT Monster1HPDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster2HPDictionary = (SELECT Monster2HPDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster3HPDictionary = (SELECT Monster3HPDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster4HPDictionary = (SELECT Monster4HPDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1AttackMultiplierDictionary = (SELECT Monster1AttackMultiplierDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1DefenseRateDictionary = (SELECT Monster1DefenseRateDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1SizeMultiplierDictionary = (SELECT Monster1SizeMultiplierDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1PoisonThresholdDictionary = (SELECT Monster1PoisonThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1SleepThresholdDictionary = (SELECT Monster1SleepThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1ParalysisThresholdDictionary = (SELECT Monster1ParalysisThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1BlastThresholdDictionary = (SELECT Monster1BlastThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1StunThresholdDictionary = (SELECT Monster1StunThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster1PartThresholdDictionary = (SELECT Monster1PartThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ Monster2PartThresholdDictionary = (SELECT Monster2PartThresholdDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ IsHighGradeEdition = (SELECT IsHighGradeEdition FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ RefreshRate = (SELECT RefreshRate FROM Quests WHERE Quests.RunID = new_Quests.RunID),
+ PartySizeDictionary = (SELECT PartySizeDictionary FROM Quests WHERE Quests.RunID = new_Quests.RunID)
+ WHERE EXISTS (SELECT 1 FROM Quests WHERE Quests.RunID = new_Quests.RunID)"
+ ;
+
+ AlterTableData(connection, sql, updateQuery, "Quests");
+ }
+
+ private void VacuumDatabaseFile(SQLiteConnection conn)
+ {
+ if (string.IsNullOrEmpty(this.dataSource))
+ {
+ Logger.Warn(CultureInfo.InvariantCulture, "Cannot vacuum database file. dataSource: {0}", this.dataSource);
+ return;
+ }
+
+ try
+ {
+ Logger.Info(CultureInfo.InvariantCulture, "Cleaning up database file: {0}", this.dataSource);
+
+ // First, force the completion of any pending operations
+ using (var pragmaCmd = new SQLiteCommand("PRAGMA schema_version;", conn))
+ {
+ pragmaCmd.ExecuteScalar();
+ }
+
+ // Now attempt the VACUUM
+ using (var vacuumCmd = new SQLiteCommand(conn))
+ {
+ // Create a new connection specifically for VACUUM
+ using (var vacuumConn = new SQLiteConnection(conn.ConnectionString))
+ {
+ vacuumConn.Open();
+ using (var cmd = new SQLiteCommand("VACUUM;", vacuumConn))
+ {
+ cmd.ExecuteNonQuery();
+ }
+ }
+ }
+
+ Logger.Info(CultureInfo.InvariantCulture, "Vacuum command finished successfully.");
+ }
+ catch (SQLiteException ex)
+ {
+ Logger.Error(CultureInfo.InvariantCulture, "Failed to vacuum database: {0}", ex.Message);
+ throw;
+ }
+ }
+
+ private void UpdateQuestsDictionariesToFiltered(SQLiteConnection conn, DataLoader dataLoader)
+ {
+ if (string.IsNullOrEmpty(this.dataSource))
+ {
+ Logger.Warn(CultureInfo.InvariantCulture, "Cannot update quests dictionaries to filtered. 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_quest_updates";
+ cmd0.ExecuteNonQuery();
+ }
+
+ using (var cmd = new SQLiteCommand(conn))
+ {
+ cmd.CommandText = "SELECT * FROM Quests";
+
+ using (var reader = cmd.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ string hitsPerSecondString = reader["HitsPerSecondDictionary"].ToString() ?? "{}";
+ string hitsTakenBlockedPerSecondString = reader["HitsTakenBlockedPerSecondDictionary"].ToString() ?? "{}";
+ string damagePerSecondString = reader["DamagePerSecondDictionary"].ToString() ?? "{}";
+ string actionsPerMinuteString = reader["ActionsPerMinuteDictionary"].ToString() ?? "{}";
+
+ var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture);
+
+ if (runID == 0)
+ {
+ continue;
+ }
+
+ var hitsPerSecondDictionary = JsonConvert.DeserializeObject>(hitsPerSecondString);
+ var hitsTakenBlockedPerSecondDictionary = JsonConvert.DeserializeObject>(hitsTakenBlockedPerSecondString);
+ var damagePerSecondDictionary = JsonConvert.DeserializeObject>(damagePerSecondString);
+ var actionsPerMinuteDictionary = JsonConvert.DeserializeObject>(actionsPerMinuteString);
+
+ Dictionary newHitsPerSecondDictionary = new();
+ Dictionary newHitsTakenBlockedPerSecondDictionary = new();
+ Dictionary newDamagePerSecondDictionary = new();
+ Dictionary newActionsPerMinuteDictionary = new();
+
+ newHitsPerSecondDictionary = TimeService.FilterFramesBySecond(hitsPerSecondDictionary);
+ newHitsTakenBlockedPerSecondDictionary = TimeService.FilterFramesBySecond(hitsTakenBlockedPerSecondDictionary);
+ newDamagePerSecondDictionary = TimeService.FilterFramesBySecond(damagePerSecondDictionary);
+ newActionsPerMinuteDictionary = TimeService.FilterFramesBySecond(actionsPerMinuteDictionary);
+
+ using (var cmd2 = new SQLiteCommand(conn))
+ {
+ cmd2.CommandText = @"UPDATE
+ Quests
+ SET
+ HitsPerSecondDictionary = @HitsPerSecondDictionary,
+ HitsTakenBlockedPerSecondDictionary = @HitsTakenBlockedPerSecondDictionary,
+ DamagePerSecondDictionary = @DamagePerSecondDictionary,
+ ActionsPerMinuteDictionary = @ActionsPerMinuteDictionary WHERE
+ RunID = @RunID";
+ cmd2.Parameters.AddWithValue("@RunID", runID);
+ cmd2.Parameters.AddWithValue("@HitsPerSecondDictionary", JsonConvert.SerializeObject(newHitsPerSecondDictionary));
+ cmd2.Parameters.AddWithValue("@HitsTakenBlockedPerSecondDictionary", JsonConvert.SerializeObject(newHitsTakenBlockedPerSecondDictionary));
+ cmd2.Parameters.AddWithValue("@DamagePerSecondDictionary", JsonConvert.SerializeObject(newDamagePerSecondDictionary));
+ cmd2.Parameters.AddWithValue("@ActionsPerMinuteDictionary", JsonConvert.SerializeObject(newActionsPerMinuteDictionary));
+
+ cmd2.ExecuteNonQuery();
+ }
+ }
+ }
+ }
+
+ using (var cmd1 = new SQLiteCommand(conn))
+ {
+ cmd1.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quest_updates
+ AFTER UPDATE ON Quests
+ FOR EACH ROW
+ WHEN NEW.YouTubeID = OLD.YouTubeID
+ BEGIN
+ SELECT RAISE(ABORT, 'Cannot update quest fields');
+ END;";
+ cmd1.ExecuteNonQuery();
+ }
+
+ // Commit the transaction
+ transaction.Commit();
+ }
+ catch (Exception ex)
+ {
+ HandleError(transaction, ex);
+ }
+ }
+
+ Logger.Debug("Updated dictionaries HitsTakenBlockedPerSecondDictionary, ActionsPerMinuteDictionary, DamagePerSecondDictionary and HitsPerSecondDictionary in Quests table");
+ }
+
private void ChangeGameFolderPath(SQLiteConnection conn)
{
if (string.IsNullOrEmpty(this.dataSource))
diff --git a/MHFZ_Overlay/Services/FileService.cs b/MHFZ_Overlay/Services/FileService.cs
index 96bbfec8..7d7e9ed3 100644
--- a/MHFZ_Overlay/Services/FileService.cs
+++ b/MHFZ_Overlay/Services/FileService.cs
@@ -38,7 +38,41 @@ public sealed class FileService
public static TimeSpan SnackbarTimeOut { get; set; } = TimeSpan.FromSeconds(5);
- public static bool OpenApplicationFolder(SnackbarPresenter snackbarPresenter, Style snackbarStyle, TimeSpan snackbarTimeout)
+ public static bool GenerateSpeedrunFiles(SnackbarPresenter snackbarPresenter, Style snackbarStyle, TimeSpan snackbarTimeout)
+ {
+ try
+ {
+ var snackbar = new Snackbar(snackbarPresenter)
+ {
+ Style = snackbarStyle,
+ Title = Messages.ErrorTitle,
+ Content = "Could not generate speedrun files",
+ Icon = new SymbolIcon(SymbolRegular.ErrorCircle24),
+ Appearance = ControlAppearance.Danger,
+ Timeout = snackbarTimeout,
+ };
+ snackbar.Show();
+ return true;
+ }
+ catch (Exception ex)
+ {
+ // TODO maybe a snackbar helper class?
+ Logger.Error(ex);
+ var snackbar = new Snackbar(snackbarPresenter)
+ {
+ Style = snackbarStyle,
+ Title = Messages.ErrorTitle,
+ Content = "Could not generate speedrun files",
+ Icon = new SymbolIcon(SymbolRegular.ErrorCircle24),
+ Appearance = ControlAppearance.Danger,
+ Timeout = snackbarTimeout,
+ };
+ snackbar.Show();
+ return false;
+ }
+ }
+
+ public static bool OpenApplicationFolder(SnackbarPresenter snackbarPresenter, Style snackbarStyle, TimeSpan snackbarTimeout)
{
try
{
diff --git a/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs b/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs
new file mode 100644
index 00000000..8b029615
--- /dev/null
+++ b/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs
@@ -0,0 +1,94 @@
+namespace MHFZ_Overlay.Services.Hotkey;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+// HotkeySettings.cs
+public class HotkeySettings
+{
+ public string OpenSettings { get; set; } = "Shift + F1";
+ public string RestartProgram { get; set; } = "Shift + F5";
+ public string CloseProgram { get; set; } = "Shift + F6";
+}
+
+public class HotkeyManager : IDisposable
+{
+ private readonly Dictionary _hotkeyActions = new();
+ private HotkeySettings _settings;
+ private readonly GlobalHotKey _globalHotKey;
+
+ public HotkeyManager()
+ {
+ _globalHotKey = new GlobalHotKey();
+ LoadSettings();
+ }
+
+
+ public void LoadSettings()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ // Load from user settings or create default
+ _settings = new HotkeySettings
+ {
+ OpenSettings = s.OpenSettingsHotkey ?? "Shift + F1",
+ RestartProgram = s.RestartProgramHotkey ?? "Shift + F5",
+ CloseProgram = s.CloseProgramHotkey ?? "Shift + F6"
+ };
+ }
+
+ public void SaveSettings()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ s.OpenSettingsHotkey = _settings.OpenSettings;
+ s.RestartProgramHotkey = _settings.RestartProgram;
+ s.CloseProgramHotkey = _settings.CloseProgram;
+ s.Save();
+ }
+
+ public void RegisterHotkeys(Action openSettings, Action restart, Action close)
+ {
+ // Store the actions
+ _hotkeyActions["OpenSettings"] = openSettings;
+ _hotkeyActions["RestartProgram"] = restart;
+ _hotkeyActions["CloseProgram"] = close;
+
+ // Register hotkeys using existing GlobalHotKey class
+ GlobalHotKey.RegisterHotKey(_settings.OpenSettings, openSettings);
+ GlobalHotKey.RegisterHotKey(_settings.RestartProgram, restart);
+ GlobalHotKey.RegisterHotKey(_settings.CloseProgram, close);
+ }
+
+ public void UpdateHotkey(string action, string newHotkey)
+ {
+ // Update the settings
+ switch (action)
+ {
+ case "OpenSettings":
+ _settings.OpenSettings = newHotkey;
+ break;
+ case "RestartProgram":
+ _settings.RestartProgram = newHotkey;
+ break;
+ case "CloseProgram":
+ _settings.CloseProgram = newHotkey;
+ break;
+ }
+
+ SaveSettings();
+
+ // Re-register the hotkey if we have an action for it
+ if (_hotkeyActions.TryGetValue(action, out var hotkeyAction))
+ {
+ GlobalHotKey.RegisterHotKey(newHotkey, hotkeyAction);
+ }
+ }
+
+ public void Dispose()
+ {
+ _globalHotKey?.Dispose();
+ }
+}
diff --git a/MHFZ_Overlay/Services/TimeService.cs b/MHFZ_Overlay/Services/TimeService.cs
index f1bb1cb5..a329b1a2 100644
--- a/MHFZ_Overlay/Services/TimeService.cs
+++ b/MHFZ_Overlay/Services/TimeService.cs
@@ -34,6 +34,27 @@ private static TimeSpan GetTimeSpanFromFrames(decimal frames)
return TimeSpan.FromSeconds((double)frames / (double)Numbers.FramesPerSecond);
}
+ public static Dictionary FilterFramesBySecond(Dictionary? originalData, int framesPerSecond = (int)Numbers.FramesPerSecond)
+ {
+ if (originalData == null || !originalData.Any())
+ return new Dictionary();
+
+ var firstFrame = originalData.Keys.Max();
+
+ return originalData
+ .OrderByDescending(x => x.Key)
+ .Aggregate(
+ new { LastFrame = firstFrame, Result = new Dictionary { { firstFrame, originalData[firstFrame] } } },
+ (acc, curr) => curr.Key == firstFrame ? acc :
+ (acc.LastFrame - curr.Key >= framesPerSecond ?
+ new
+ {
+ LastFrame = curr.Key,
+ Result = new Dictionary(acc.Result) { [curr.Key] = curr.Value }
+ } : acc),
+ acc => acc.Result);
+ }
+
public static string GetTimeLeftPercent(decimal timeDefInt, decimal timeInt, bool isDure)
{
if (timeDefInt < timeInt || timeDefInt <= 0)
diff --git a/MHFZ_Overlay/Settings.Designer.cs b/MHFZ_Overlay/Settings.Designer.cs
index 2657a844..d2dbaa39 100644
--- a/MHFZ_Overlay/Settings.Designer.cs
+++ b/MHFZ_Overlay/Settings.Designer.cs
@@ -4162,5 +4162,41 @@ public bool EnableAchievementsTracking {
this["EnableAchievementsTracking"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F1")]
+ public string OpenSettingsHotkey {
+ get {
+ return ((string)(this["OpenSettingsHotkey"]));
+ }
+ set {
+ this["OpenSettingsHotkey"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F5")]
+ public string RestartProgramHotkey {
+ get {
+ return ((string)(this["RestartProgramHotkey"]));
+ }
+ set {
+ this["RestartProgramHotkey"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F6")]
+ public string CloseProgramHotkey {
+ get {
+ return ((string)(this["CloseProgramHotkey"]));
+ }
+ set {
+ this["CloseProgramHotkey"] = value;
+ }
+ }
}
}
diff --git a/MHFZ_Overlay/Settings.settings b/MHFZ_Overlay/Settings.settings
index 17bf6b45..3d979bad 100644
--- a/MHFZ_Overlay/Settings.settings
+++ b/MHFZ_Overlay/Settings.settings
@@ -1037,5 +1037,14 @@
True
+
+ Shift + F1
+
+
+ Shift + F5
+
+
+ Shift + F6
+
\ No newline at end of file
diff --git a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs
index 3277abcc..15290f9d 100644
--- a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs
+++ b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs
@@ -4314,7 +4314,7 @@ public string Monster1HP
}
///
- /// Gets the name of the rank.
+ /// Gets the name of the rank.TODO: In database the spaces are there.
///
/// The identifier.
///
@@ -12204,6 +12204,10 @@ public double CalculateHitsPerSecond()
public int PreviousDualSwordsSharpens { get; set; }
+ public Dictionary PartySizeDictionary { get; set; } = new();
+
+ public int PreviousPartySize { get; set; }
+
// Get all countries
public static IEnumerable Countries => RestCountriesService.GetAllCountries();
@@ -13289,6 +13293,19 @@ public void InsertQuestInfoIntoDictionaries()
LoggerInstance.Warn(ex, "Could not insert into DualSwordsSharpensDictionary");
}
}
+
+ if (this.PreviousPartySize != this.PartySize() && !this.PartySizeDictionary.ContainsKey(this.TimeInt()))
+ {
+ try
+ {
+ this.PreviousPartySize = this.PartySize();
+ this.PartySizeDictionary.Add(this.TimeInt(), this.PartySize());
+ }
+ catch (Exception ex)
+ {
+ LoggerInstance.Warn(ex, "Could not insert into PartySizeDictionary");
+ }
+ }
}
public void ResetQuestInfoVariables()
@@ -13426,6 +13443,7 @@ public void ResetQuestInfoVariables()
this.PreviousMonster2Part9Threshold = 0;
this.PreviousMonster2Part10Threshold = 0;
this.PreviousDualSwordsSharpens = 0;
+ this.PreviousPartySize = 0;
}
public void ClearQuestInfoDictionaries()
@@ -13466,6 +13484,7 @@ public void ClearQuestInfoDictionaries()
this.Monster2PartThresholdDictionary.Clear();
this.DualSwordsSharpensDictionary.Clear();
+ this.PartySizeDictionary.Clear();
}
public void ClearGraphCollections()
diff --git a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml
index b818139d..5f653f8e 100644
--- a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml
+++ b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml
@@ -1543,38 +1543,42 @@
+
-
+
-
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
Current
Final
-
+
-
+
-
-
-
+
+
+
@@ -1601,30 +1605,30 @@
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
-
+
+
-
+
@@ -1643,39 +1647,39 @@
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
diff --git a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml.cs
index 15f7bdea..880b090d 100644
--- a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml.cs
+++ b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml.cs
@@ -1148,6 +1148,8 @@ private async Task GetRepoStats()
private void OpenOverlayFolder_Click(object sender, RoutedEventArgs e) => FileService.OpenApplicationFolder(this.ConfigWindowSnackBarPresenter, (Style)this.FindResource("CatppuccinMochaSnackBar"), this.SnackbarTimeOut);
+ private void GenerateSpeedrunFiles_Click(object sender, RoutedEventArgs e) => FileService.GenerateSpeedrunFiles(this.ConfigWindowSnackBarPresenter, (Style)this.FindResource("CatppuccinMochaSnackBar"), this.SnackbarTimeOut);
+
private void OpenSettingsFolder_Click(object sender, RoutedEventArgs e)
{
try
diff --git a/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml
new file mode 100644
index 00000000..e1660d73
--- /dev/null
+++ b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Press hotkey combination to set. Press Escape to clear. Each hotkey must include at least one modifier (Ctrl, Alt, Shift, or Win).
+
+
+
+
+
+
+
+
+
diff --git a/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs
new file mode 100644
index 00000000..2a3f98ac
--- /dev/null
+++ b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs
@@ -0,0 +1,98 @@
+namespace MHFZ_Overlay.Views.Windows;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using MHFZ_Overlay.Services.Hotkey;
+using Wpf.Ui.Controls;
+
+// HotkeySettingsWindow.xaml.cs
+public partial class HotkeySettingsWindow : FluentWindow
+{
+ private readonly HotkeyManager _hotkeyManager;
+ private readonly Dictionary _originalHotkeys = new();
+
+ public HotkeySettingsWindow(HotkeyManager hotkeyManager)
+ {
+ this.InitializeComponent();
+ _hotkeyManager = hotkeyManager;
+ LoadCurrentHotkeys();
+ }
+
+ private void LoadCurrentHotkeys()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ this.OpenSettingsHotkey.Text = s.OpenSettingsHotkey;
+ this.RestartProgramHotkey.Text = s.RestartProgramHotkey;
+ this.CloseProgramHotkey.Text = s.CloseProgramHotkey;
+
+ // Store original values for cancellation
+ _originalHotkeys[this.OpenSettingsHotkey] = s.OpenSettingsHotkey;
+ _originalHotkeys[this.RestartProgramHotkey] = s.RestartProgramHotkey;
+ _originalHotkeys[this.CloseProgramHotkey] = s.CloseProgramHotkey;
+ }
+
+ private void Hotkey_PreviewKeyDown(object sender, KeyEventArgs e)
+ {
+ e.Handled = true;
+ var textBox = (System.Windows.Controls.TextBox)sender;
+
+ var key = e.Key == Key.System ? e.SystemKey : e.Key;
+ if (key == Key.Escape)
+ {
+ textBox.Text = _originalHotkeys[textBox];
+ return;
+ }
+
+ var modifiers = new List();
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
+ modifiers.Add("Ctrl");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
+ modifiers.Add("Shift");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
+ modifiers.Add("Alt");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Windows))
+ modifiers.Add("Win");
+
+ if (key != Key.LeftCtrl && key != Key.RightCtrl &&
+ key != Key.LeftAlt && key != Key.RightAlt &&
+ key != Key.LeftShift && key != Key.RightShift &&
+ key != Key.LWin && key != Key.RWin)
+ {
+ if (modifiers.Count == 0)
+ {
+ System.Windows.MessageBox.Show("Hotkey must include at least one modifier (Ctrl, Alt, Shift, or Win)",
+ "Invalid Hotkey", System.Windows.MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ var hotkeyString = string.Join(" + ", modifiers.Concat(new[] { key.ToString() }));
+ textBox.Text = hotkeyString;
+ }
+ }
+
+ private void SaveButton_Click(object sender, RoutedEventArgs e)
+ {
+ _hotkeyManager.UpdateHotkey("OpenSettings", this.OpenSettingsHotkey.Text);
+ _hotkeyManager.UpdateHotkey("RestartProgram", this.RestartProgramHotkey.Text);
+ _hotkeyManager.UpdateHotkey("CloseProgram", this.CloseProgramHotkey.Text);
+ DialogResult = true;
+ Close();
+ }
+
+ private void CancelButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = false;
+ Close();
+ }
+}
diff --git a/MHFZ_Overlay/Views/Windows/MainWindow.xaml b/MHFZ_Overlay/Views/Windows/MainWindow.xaml
index 1375d664..09d48635 100644
--- a/MHFZ_Overlay/Views/Windows/MainWindow.xaml
+++ b/MHFZ_Overlay/Views/Windows/MainWindow.xaml
@@ -40,6 +40,11 @@
x:Name="MainWindowNotifyIcon">
+
+
+
+
+
diff --git a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
index 7c40f887..f7d1d1c1 100644
--- a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
+++ b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
@@ -128,10 +128,28 @@ private void CreateSystemTrayIcon()
_mainWindowNotifyIcon = this.MainWindowNotifyIcon;
}
+ // Add method to open hotkey settings
+ private void OpenHotkeySettings()
+ {
+ var settingsWindow = new HotkeySettingsWindow(_hotkeyManager);
+ settingsWindow.Owner = this; // Make it a child window of MainWindow
+ settingsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ settingsWindow.ShowDialog();
+ }
+
+ // Ensure proper cleanup. TODO test
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+ _hotkeyManager?.Dispose();
+ }
+
private void NotifyIcon_Click(object sender, RoutedEventArgs e) => this.OpenConfigButton_Key();
private void OptionSettings_Click(object sender, RoutedEventArgs e) => this.OpenConfigButton_Key();
+ private void OptionHotkeys_Click(object sender, RoutedEventArgs e) => this.OpenHotkeySettings();
+
private void OptionHelp_Click(object sender, RoutedEventArgs e) => OpenLink("https://github.com/DorielRivalet/mhfz-overlay/blob/main/FAQ.md");
private void OptionDocumentation_Click(object sender, RoutedEventArgs e) => OpenLink("https://github.com/DorielRivalet/mhfz-overlay/tree/main/docs");
@@ -270,6 +288,9 @@ private void OptionDatabaseFolder_Click(object sender, RoutedEventArgs e)
private double? xOffset { get; set; }
+ private readonly HotkeyManager _hotkeyManager;
+
+
///
/// Initializes a new instance of the class.
///
@@ -281,6 +302,8 @@ public MainWindow()
// Start the stopwatch
stopwatch.Start();
+ _hotkeyManager = new HotkeyManager();
+
var splashScreen = new SplashScreen("../../Assets/Icons/png/loading.png");
splashScreen.Show(false);
@@ -304,9 +327,12 @@ public MainWindow()
ViewModels.Windows.AddressModel.ValidateGameFolder();
this.DataContext = this.DataLoader.Model;
- GlobalHotKey.RegisterHotKey("Shift + F1", () => this.OpenConfigButton_Key());
- GlobalHotKey.RegisterHotKey("Shift + F5", () => ReloadButton_Key());
- GlobalHotKey.RegisterHotKey("Shift + F6", () => CloseButton_Key());
+ // Replace your existing hotkey registration with this:
+ _hotkeyManager.RegisterHotkeys(
+ () => this.OpenConfigButton_Key(),
+ () => this.ReloadButton_Key(),
+ () => this.CloseButton_Key()
+ );
DiscordService.InitializeDiscordRPC();
this.CheckGameState();
@@ -1624,7 +1650,7 @@ private void OpenConfigButton_Click(object sender, RoutedEventArgs e)
private void CloseButton_Click(object sender, RoutedEventArgs e) => ApplicationService.HandleShutdown();
// https://stackoverflow.com/questions/4773632/how-do-i-restart-a-wpf-application
- private static void ReloadButton_Key() => ApplicationService.HandleRestart();
+ private void ReloadButton_Key() => ApplicationService.HandleRestart();
private void OpenConfigButton_Key()
{
@@ -1665,7 +1691,7 @@ private void OpenConfigButton_Key()
}
}
- private static void CloseButton_Key() => ApplicationService.HandleShutdown();
+ private void CloseButton_Key() => ApplicationService.HandleShutdown();
private void MainGrid_MouseMove(object sender, MouseEventArgs e) => DoDragDrop(this.movingObject);
diff --git a/README.md b/README.md
index 4e2073c1..93429e37 100644
--- a/README.md
+++ b/README.md
@@ -125,10 +125,12 @@ We strongly recommend that you verify the authenticity and integrity of the soft
- `Shift+F5` Restart Overlay.
- `Shift+F6` Exit.
-As an alternative to hotkeys, you can use the system tray options by right-clicking the icon.
+As an alternative to hotkeys, you can use the system tray options by right-clicking the icon. You can change the hotkeys by opening the Hotkeys window, found in the system tray menu.
![System Tray options](./demo/systemtray.png)
+![Hotkeys options](./demo/hotkeys.png)
+
### Quick Troubleshooting
- Use the Configuration Preset option for quickly setting up your configuration.
diff --git a/demo/hotkeys.png b/demo/hotkeys.png
new file mode 100644
index 00000000..46c521a4
Binary files /dev/null and b/demo/hotkeys.png differ
diff --git a/img/monster/azure_rathalos.png b/img/monster/azure_rathalos.png
index bf4293f2..6d402a51 100644
Binary files a/img/monster/azure_rathalos.png and b/img/monster/azure_rathalos.png differ
diff --git a/img/monster/azure_rathalos.webp b/img/monster/azure_rathalos.webp
new file mode 100644
index 00000000..f4764c5f
Binary files /dev/null and b/img/monster/azure_rathalos.webp differ
diff --git a/img/monster/conquest_shantien.png b/img/monster/conquest_shantien.png
index 842e8ea5..f8d65500 100644
Binary files a/img/monster/conquest_shantien.png and b/img/monster/conquest_shantien.png differ
diff --git a/img/monster/conquest_shantien.webp b/img/monster/conquest_shantien.webp
new file mode 100644
index 00000000..13840efd
Binary files /dev/null and b/img/monster/conquest_shantien.webp differ
diff --git a/img/monster/disufiroa.png b/img/monster/disufiroa.png
index 8b9fb4f1..a3c9f6c8 100644
Binary files a/img/monster/disufiroa.png and b/img/monster/disufiroa.png differ
diff --git a/img/monster/disufiroa.webp b/img/monster/disufiroa.webp
new file mode 100644
index 00000000..87bbe3d3
Binary files /dev/null and b/img/monster/disufiroa.webp differ
diff --git a/img/monster/gold_rathian.png b/img/monster/gold_rathian.png
index c0e9a9e4..3a295066 100644
Binary files a/img/monster/gold_rathian.png and b/img/monster/gold_rathian.png differ
diff --git a/img/monster/gold_rathian.webp b/img/monster/gold_rathian.webp
new file mode 100644
index 00000000..87e67912
Binary files /dev/null and b/img/monster/gold_rathian.webp differ
diff --git a/img/monster/pink_rathian.png b/img/monster/pink_rathian.png
index d6943ebe..2c6ca688 100644
Binary files a/img/monster/pink_rathian.png and b/img/monster/pink_rathian.png differ
diff --git a/img/monster/pink_rathian.webp b/img/monster/pink_rathian.webp
new file mode 100644
index 00000000..082ef167
Binary files /dev/null and b/img/monster/pink_rathian.webp differ
diff --git a/img/monster/rathalos.png b/img/monster/rathalos.png
index e3b1bb02..baa4cf39 100644
Binary files a/img/monster/rathalos.png and b/img/monster/rathalos.png differ
diff --git a/img/monster/rathalos.webp b/img/monster/rathalos.webp
new file mode 100644
index 00000000..9fc2a520
Binary files /dev/null and b/img/monster/rathalos.webp differ
diff --git a/img/monster/rathian.png b/img/monster/rathian.png
index 3abb2cf6..1922e43e 100644
Binary files a/img/monster/rathian.png and b/img/monster/rathian.png differ
diff --git a/img/monster/rathian.webp b/img/monster/rathian.webp
new file mode 100644
index 00000000..644c56e9
Binary files /dev/null and b/img/monster/rathian.webp differ
diff --git a/img/monster/shantien.png b/img/monster/shantien.png
index 70504cfd..57e9b072 100644
Binary files a/img/monster/shantien.png and b/img/monster/shantien.png differ
diff --git a/img/monster/shantien.webp b/img/monster/shantien.webp
new file mode 100644
index 00000000..afcfbc55
Binary files /dev/null and b/img/monster/shantien.webp differ
diff --git a/img/monster/shiten_disufiroa.png b/img/monster/shiten_disufiroa.png
index bc8650a7..9f68a205 100644
Binary files a/img/monster/shiten_disufiroa.png and b/img/monster/shiten_disufiroa.png differ
diff --git a/img/monster/shiten_disufiroa.webp b/img/monster/shiten_disufiroa.webp
new file mode 100644
index 00000000..19c055f5
Binary files /dev/null and b/img/monster/shiten_disufiroa.webp differ
diff --git a/img/monster/shiten_unknown.gif b/img/monster/shiten_unknown.gif
new file mode 100644
index 00000000..482eb985
Binary files /dev/null and b/img/monster/shiten_unknown.gif differ
diff --git a/img/monster/shiten_unknown.png b/img/monster/shiten_unknown.png
index 2ab2da42..7c919ef3 100644
Binary files a/img/monster/shiten_unknown.png and b/img/monster/shiten_unknown.png differ
diff --git a/img/monster/shiten_unknown.webp b/img/monster/shiten_unknown.webp
new file mode 100644
index 00000000..e4c140ef
Binary files /dev/null and b/img/monster/shiten_unknown.webp differ
diff --git a/img/monster/shiten_unknown_phase2.png b/img/monster/shiten_unknown_phase2.png
new file mode 100644
index 00000000..0594fd6f
Binary files /dev/null and b/img/monster/shiten_unknown_phase2.png differ
diff --git a/img/monster/shiten_unknown_phase2.webp b/img/monster/shiten_unknown_phase2.webp
new file mode 100644
index 00000000..d33df936
Binary files /dev/null and b/img/monster/shiten_unknown_phase2.webp differ
diff --git a/img/monster/shiten_unknown_phase3.png b/img/monster/shiten_unknown_phase3.png
new file mode 100644
index 00000000..730abe64
Binary files /dev/null and b/img/monster/shiten_unknown_phase3.png differ
diff --git a/img/monster/shiten_unknown_phase3.webp b/img/monster/shiten_unknown_phase3.webp
new file mode 100644
index 00000000..17c23a06
Binary files /dev/null and b/img/monster/shiten_unknown_phase3.webp differ
diff --git a/img/monster/shiten_unknown_phase4.png b/img/monster/shiten_unknown_phase4.png
new file mode 100644
index 00000000..1eb716b0
Binary files /dev/null and b/img/monster/shiten_unknown_phase4.png differ
diff --git a/img/monster/shiten_unknown_phase4.webp b/img/monster/shiten_unknown_phase4.webp
new file mode 100644
index 00000000..6ccdf93c
Binary files /dev/null and b/img/monster/shiten_unknown_phase4.webp differ
diff --git a/img/monster/shiten_unknown_phase5.png b/img/monster/shiten_unknown_phase5.png
new file mode 100644
index 00000000..da26ddd5
Binary files /dev/null and b/img/monster/shiten_unknown_phase5.png differ
diff --git a/img/monster/shiten_unknown_phase5.webp b/img/monster/shiten_unknown_phase5.webp
new file mode 100644
index 00000000..f89d07e9
Binary files /dev/null and b/img/monster/shiten_unknown_phase5.webp differ
diff --git a/img/monster/shiten_unknown_phase6.png b/img/monster/shiten_unknown_phase6.png
new file mode 100644
index 00000000..471c846f
Binary files /dev/null and b/img/monster/shiten_unknown_phase6.png differ
diff --git a/img/monster/shiten_unknown_phase6.webp b/img/monster/shiten_unknown_phase6.webp
new file mode 100644
index 00000000..3a47bbd6
Binary files /dev/null and b/img/monster/shiten_unknown_phase6.webp differ
diff --git a/img/monster/shiten_unknown_phase7.png b/img/monster/shiten_unknown_phase7.png
new file mode 100644
index 00000000..59409905
Binary files /dev/null and b/img/monster/shiten_unknown_phase7.png differ
diff --git a/img/monster/shiten_unknown_phase7.webp b/img/monster/shiten_unknown_phase7.webp
new file mode 100644
index 00000000..f3662259
Binary files /dev/null and b/img/monster/shiten_unknown_phase7.webp differ
diff --git a/img/monster/shiten_unknown_phase8.png b/img/monster/shiten_unknown_phase8.png
new file mode 100644
index 00000000..21442b3f
Binary files /dev/null and b/img/monster/shiten_unknown_phase8.png differ
diff --git a/img/monster/shiten_unknown_phase8.webp b/img/monster/shiten_unknown_phase8.webp
new file mode 100644
index 00000000..f7bd6f5d
Binary files /dev/null and b/img/monster/shiten_unknown_phase8.webp differ
diff --git a/img/monster/silver_rathalos.png b/img/monster/silver_rathalos.png
index a43afd33..c096936e 100644
Binary files a/img/monster/silver_rathalos.png and b/img/monster/silver_rathalos.png differ
diff --git a/img/monster/silver_rathalos.webp b/img/monster/silver_rathalos.webp
new file mode 100644
index 00000000..545b7aaf
Binary files /dev/null and b/img/monster/silver_rathalos.webp differ
diff --git a/img/monster/unknown.png b/img/monster/unknown.png
index 76267bfc..0467c9a3 100644
Binary files a/img/monster/unknown.png and b/img/monster/unknown.png differ
diff --git a/img/monster/unknown.webp b/img/monster/unknown.webp
new file mode 100644
index 00000000..99ab3763
Binary files /dev/null and b/img/monster/unknown.webp differ
diff --git a/package-lock.json b/package-lock.json
index 200a40cb..a72ee92e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mhfz_overlay",
- "version": "0.40.0",
+ "version": "0.41.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "mhfz_overlay",
- "version": "0.40.0",
+ "version": "0.41.0",
"license": "MIT",
"dependencies": {
"@release-it/conventional-changelog": "^8.0.1",
diff --git a/package.json b/package.json
index f37f04dd..7e1a1f9d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mhfz_overlay",
- "version": "0.40.0",
+ "version": "0.41.0",
"description": "[![Monster Hunter Frontier Z Overlay v0.21.0 Preview](./demo/youtubepreview1.jpg)](https://www.youtube.com/watch?v=A9ffbRICqZY \"Monster Hunter Frontier Z Overlay v0.21.0 Preview\")",
"main": "MHFZ_Overlay.sln",
"scripts": {