diff --git a/lib/libimhex/include/hex/api/event_manager.hpp b/lib/libimhex/include/hex/api/event_manager.hpp index 43da0a12b..bb6474d4e 100644 --- a/lib/libimhex/include/hex/api/event_manager.hpp +++ b/lib/libimhex/include/hex/api/event_manager.hpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -253,7 +254,12 @@ namespace hex { EVENT_DEF(EventWindowInitialized); EVENT_DEF(EventWindowDeinitializing, GLFWwindow *); EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&); - EVENT_DEF(EventPatchCreated, u64, u8, u8); + + /** + * @brief Called upon creation of an IPS patch. + * As for now, the event only serves a purpose for the achievement unlock. + */ + EVENT_DEF(EventPatchCreated, const u8*, u64, const PatchKind); EVENT_DEF(EventPatternEvaluating); EVENT_DEF(EventPatternExecuted, const std::string&); EVENT_DEF(EventPatternEditorChanged, const std::string&); diff --git a/lib/libimhex/include/hex/helpers/patches.hpp b/lib/libimhex/include/hex/helpers/patches.hpp index 8fe97341b..ffef8932b 100644 --- a/lib/libimhex/include/hex/helpers/patches.hpp +++ b/lib/libimhex/include/hex/helpers/patches.hpp @@ -21,6 +21,11 @@ namespace hex { MissingEOF }; + enum class PatchKind { + IPS, + IPS32 + }; + class Patches { public: Patches() = default; diff --git a/plugins/builtin/source/content/achievements.cpp b/plugins/builtin/source/content/achievements.cpp index 473eb24bc..e8d34bd76 100644 --- a/plugins/builtin/source/content/achievements.cpp +++ b/plugins/builtin/source/content/achievements.cpp @@ -1,8 +1,10 @@ +#include #include #include #include #include +#include #include #include @@ -192,10 +194,16 @@ namespace hex::plugin::builtin { AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.create_bookmark.name"); }); - EventPatchCreated::subscribe([](u64, u8, u8) { + EventProviderDataModified::subscribe([](const prv::Provider *, u64, const u64, const u8*) { + // Warning: overlaps with the "Flood fill" achievement, since "Fill" works by writing to bytes one-by-one. + // Thus, we do not check for size, that will always be equal to 1 even during a fill operation. AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.modify_byte.name"); }); + EventPatchCreated::subscribe([](const u8 *, u8, PatchKind) { + AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.create_patch.name"); + }); + EventImHexStartupFinished::subscribe(AchievementManager::loadProgress); EventAchievementUnlocked::subscribe([](const Achievement &) { diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index 67c02913f..129b91b75 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -297,12 +297,12 @@ namespace hex::plugin::builtin { } if (data.has_value()) { - file.writeVector(data.value()); + const auto& bytes = data.value(); + file.writeVector(bytes); + EventPatchCreated::post(bytes.data(), bytes.size(), PatchKind::IPS); } else { handleIPSError(data.error()); } - - AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.create_patch.name"); }); }); }); @@ -336,12 +336,12 @@ namespace hex::plugin::builtin { } if (data.has_value()) { - file.writeVector(data.value()); + const std::vector& bytes = data.value(); + file.writeVector(bytes); + EventPatchCreated::post(bytes.data(), bytes.size(), PatchKind::IPS32); } else { handleIPSError(data.error()); } - - AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.create_patch.name"); }); }); });