Add callback for mod reordering and functions to get mod file path and order index (#99)
Some checks failed
validate / windows (x64, Release) (push) Has been cancelled
validate / ubuntu (arm64, Debug) (push) Has been cancelled
validate / ubuntu (arm64, Release) (push) Has been cancelled
validate / ubuntu (x64, Debug) (push) Has been cancelled
validate / ubuntu (x64, Release) (push) Has been cancelled
validate / windows (x64, Debug) (push) Has been cancelled
validate / macos (arm64, Debug) (push) Has been cancelled
validate / macos (arm64, Release) (push) Has been cancelled
validate / macos (x64, Debug) (push) Has been cancelled
validate / macos (x64, Release) (push) Has been cancelled

This commit is contained in:
Wiseguy 2025-04-06 22:14:13 -04:00 committed by GitHub
parent 8506c1b588
commit af075623dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 9 deletions

View file

@ -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<ModDetails> get_details_for_mod(const std::string& mod_id);
std::vector<ModDetails> 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<ModLoadErrorDetails> 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<ModDetails> get_details_for_mod(const std::string& mod_id) const;
std::vector<ModDetails> 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<ModDetails> get_details_for_mod(const std::string& mod_id);
std::vector<ModDetails> 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<ModContentTypeId>& content_types, bool requires_manifest);

View file

@ -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<size_t>(-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<size_t>(-1);
}
return find_order_it - opened_mods_order.begin();
}
std::optional<recomp::mods::ModDetails> 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());
}

View file

@ -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::ModDetails> 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);