diff --git a/librecomp/include/librecomp/mods.hpp b/librecomp/include/librecomp/mods.hpp index eeb41bd..9e11f68 100644 --- a/librecomp/include/librecomp/mods.hpp +++ b/librecomp/include/librecomp/mods.hpp @@ -260,9 +260,6 @@ namespace recomp { mod_id(mod_id_), error(error_), error_param(error_param_) {} }; - std::string get_mod_id_from_filename(const std::filesystem::path& mod_filename); - std::optional get_details_for_mod(const std::string& mod_id); - std::vector get_all_mod_details(const std::string& mod_game_id); void set_mod_index(const std::string &mod_game_id, const std::string &mod_id, size_t index); // Internal functions, TODO move to an internal header. @@ -277,6 +274,7 @@ namespace recomp { class ModHandle; using content_enabled_callback = void(ModContext&, const ModHandle&); using content_disabled_callback = void(ModContext&, const ModHandle&); + using content_reordered_callback = void(ModContext&); struct ModContentType { // The file that's used to indicate that a mod contains this content type. @@ -288,6 +286,11 @@ namespace recomp { content_enabled_callback* on_enabled; // Function to call when an instance of this content type is disabled. content_disabled_callback* on_disabled; + // Function to call when an instance of this content type has been reordered. + // No mod handle is provided as multiple instances may have been reordered at the same time. + // Will not be called if an instance of this content type was incidentally reordered due + // to the reordering of another mod, as the ordering of just instances of this content type will not have changed. + content_reordered_callback* on_reordered; }; // Holds IDs for mod content types, which get assigned as they're registered. @@ -336,6 +339,8 @@ namespace recomp { std::vector load_mods(const GameEntry& game_entry, uint8_t* rdram, int32_t load_address, uint32_t& ram_used); void unload_mods(); std::string get_mod_id_from_filename(const std::filesystem::path& mod_filename) const; + std::filesystem::path get_mod_filename(const std::string& mod_id) const; + size_t get_mod_order_index(const std::string& mod_id) const; std::optional get_details_for_mod(const std::string& mod_id) const; std::vector get_all_mod_details(const std::string& mod_game_id); void set_mod_index(const std::string &mod_game_id, const std::string &mod_id, size_t index); @@ -579,6 +584,8 @@ namespace recomp { void scan_mods(); void close_mods(); std::filesystem::path get_mods_directory(); + std::optional get_details_for_mod(const std::string& mod_id); + std::vector get_all_mod_details(const std::string& mod_game_id); void enable_mod(const std::string& mod_id, bool enabled); bool is_mod_enabled(const std::string& mod_id); bool is_mod_auto_enabled(const std::string& mod_id); @@ -588,6 +595,9 @@ namespace recomp { void set_mod_config_value(const std::string &mod_id, const std::string &option_id, const ConfigValueVariant &value); ConfigValueVariant get_mod_config_value(size_t mod_index, const std::string &option_id); ConfigValueVariant get_mod_config_value(const std::string &mod_id, const std::string &option_id); + std::string get_mod_id_from_filename(const std::filesystem::path& mod_filename); + std::filesystem::path get_mod_filename(const std::string& mod_id); + size_t get_mod_order_index(const std::string& mod_id); ModContentTypeId register_mod_content_type(const ModContentType& type); bool register_mod_container_type(const std::string& extension, const std::vector& content_types, bool requires_manifest); diff --git a/librecomp/src/mods.cpp b/librecomp/src/mods.cpp index b58a701..b39c763 100644 --- a/librecomp/src/mods.cpp +++ b/librecomp/src/mods.cpp @@ -614,7 +614,10 @@ recomp::mods::ModLoadError recomp::mods::ModContext::load_mod(recomp::mods::ModH } for (ModContentTypeId type_id : mod.content_types) { - content_types[type_id.value].on_enabled(*this, mod); + content_enabled_callback* callback = content_types[type_id.value].on_enabled; + if (callback) { + callback(*this, mod); + } } return ModLoadError::Good; @@ -872,7 +875,8 @@ recomp::mods::ModContext::ModContext() { .content_filename = std::string{modpaths::binary_syms_path}, .allow_runtime_toggle = false, .on_enabled = ModContext::on_code_mod_enabled, - .on_disabled = nullptr + .on_disabled = nullptr, + .on_reordered = nullptr }; code_content_type_id = register_content_type(code_content_type); @@ -969,7 +973,10 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable // If mods have been loaded and a mod was successfully enabled by this call, call the on_enabled handlers for its content types. if (was_enabled && mods_loaded) { for (ModContentTypeId type_id : mod.content_types) { - content_types[type_id.value].on_enabled(*this, mod); + content_enabled_callback* callback = content_types[type_id.value].on_enabled; + if (callback) { + callback(*this, mod); + } } } @@ -990,7 +997,10 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable if (mods_loaded) { for (ModContentTypeId type_id : mod_from_stack_handle.content_types) { - content_types[type_id.value].on_enabled(*this, mod_from_stack_handle); + content_enabled_callback* callback = content_types[type_id.value].on_enabled; + if (callback) { + callback(*this, mod_from_stack_handle); + } } } } @@ -1005,7 +1015,10 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable // If mods have been loaded and a mod was successfully disabled by this call, call the on_disabled handlers for its content types. if (was_disabled && mods_loaded) { for (ModContentTypeId type_id : mod.content_types) { - content_types[type_id.value].on_disabled(*this, mod); + content_disabled_callback* callback = content_types[type_id.value].on_disabled; + if (callback) { + callback(*this, mod); + } } } @@ -1040,7 +1053,10 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable if (enabled_mod_it != opened_mods_by_id.end()) { const ModHandle &enabled_mod_handle = opened_mods[enabled_mod_it->second]; for (ModContentTypeId type_id : enabled_mod_handle.content_types) { - content_types[type_id.value].on_disabled(*this, enabled_mod_handle); + content_disabled_callback* callback = content_types[type_id.value].on_disabled; + if (callback) { + callback(*this, enabled_mod_handle); + } } } } @@ -1077,6 +1093,31 @@ std::string recomp::mods::ModContext::get_mod_id_from_filename(const std::filesy return opened_mods[find_it->second].manifest.mod_id; } +std::filesystem::path recomp::mods::ModContext::get_mod_filename(const std::string& mod_id) const { + auto find_it = opened_mods_by_id.find(mod_id); + if (find_it == opened_mods_by_id.end()) { + return {}; + } + + return opened_mods[find_it->second].manifest.mod_root_path; +} + +size_t recomp::mods::ModContext::get_mod_order_index(const std::string& mod_id) const { + auto find_it = opened_mods_by_id.find(mod_id); + if (find_it == opened_mods_by_id.end()) { + return static_cast(-1); + } + + // TODO keep a mapping of mod index to mod order index to prevent needing a lookup here. + auto find_order_it = std::find(opened_mods_order.begin(), opened_mods_order.end(), find_it->second); + if (find_order_it == opened_mods_order.end()) { + assert(false); + return static_cast(-1); + } + + return find_order_it - opened_mods_order.begin(); +} + std::optional recomp::mods::ModContext::get_details_for_mod(const std::string& mod_id) const { auto find_it = opened_mods_by_id.find(mod_id); if (find_it == opened_mods_by_id.end()) { @@ -1272,6 +1313,13 @@ void recomp::mods::ModContext::set_mod_index(const std::string &mod_game_id, con opened_mods_order.push_back(mod_index); } + for (ModContentTypeId type_id : opened_mods[mod_index].content_types) { + content_reordered_callback* callback = content_types[type_id.value].on_reordered; + if (callback) { + callback(*this); + } + } + mod_configuration_thread_queue.enqueue(ModConfigQueueSave()); } diff --git a/librecomp/src/recomp.cpp b/librecomp/src/recomp.cpp index 640e285..169654c 100644 --- a/librecomp/src/recomp.cpp +++ b/librecomp/src/recomp.cpp @@ -563,6 +563,16 @@ std::string recomp::mods::get_mod_id_from_filename(const std::filesystem::path& return mod_context->get_mod_id_from_filename(mod_filename); } +std::filesystem::path recomp::mods::get_mod_filename(const std::string& mod_id) { + std::lock_guard lock { mod_context_mutex }; + return mod_context->get_mod_filename(mod_id); +} + +size_t recomp::mods::get_mod_order_index(const std::string& mod_id) { + std::lock_guard lock { mod_context_mutex }; + return mod_context->get_mod_order_index(mod_id); +} + std::optional recomp::mods::get_details_for_mod(const std::string& mod_id) { std::lock_guard lock { mod_context_mutex }; return mod_context->get_details_for_mod(mod_id);