Add deprecated mod support.

This commit is contained in:
Dario 2026-01-29 00:08:36 -03:00
parent 949f40520b
commit 8693dbdd35
3 changed files with 66 additions and 3 deletions

View file

@ -153,6 +153,14 @@ namespace recomp {
WrongVersion = 3 WrongVersion = 3
}; };
enum class DeprecationStatus {
// Status is unknown.
Unknown,
// The mod was integrated as part of the project.
Integrated
};
struct ModFileHandle { struct ModFileHandle {
virtual ~ModFileHandle() = default; virtual ~ModFileHandle() = default;
virtual std::vector<char> read_file(const std::string& filepath, bool& exists) const = 0; virtual std::vector<char> read_file(const std::string& filepath, bool& exists) const = 0;
@ -321,12 +329,15 @@ namespace recomp {
void register_game(const std::string& mod_game_id); void register_game(const std::string& mod_game_id);
void register_embedded_mod(const std::string& mod_id, std::span<const uint8_t> mod_bytes); void register_embedded_mod(const std::string& mod_id, std::span<const uint8_t> mod_bytes);
void register_deprecated_mod(const std::string& mod_id, DeprecationStatus deprecation_status);
std::vector<ModOpenErrorDetails> scan_mod_folder(const std::filesystem::path& mod_folder); std::vector<ModOpenErrorDetails> scan_mod_folder(const std::filesystem::path& mod_folder);
void close_mods(); void close_mods();
void load_mods_config(); void load_mods_config();
void enable_mod(const std::string& mod_id, bool enabled, bool trigger_save); void enable_mod(const std::string& mod_id, bool enabled, bool trigger_save);
bool is_mod_enabled(const std::string& mod_id) const; bool is_mod_enabled(const std::string& mod_id) const;
bool is_mod_auto_enabled(const std::string& mod_id) const; bool is_mod_auto_enabled(const std::string& mod_id) const;
bool is_mod_deprecated(const std::string& mod_id) const;
DeprecationStatus get_mod_deprecation_status(const std::string& mod_id) const;
size_t num_opened_mods(); size_t num_opened_mods();
std::vector<ModLoadErrorDetails> load_mods(const GameEntry& game_entry, const std::string& game_mode_id, uint8_t* rdram, int32_t load_address, uint32_t& ram_used); std::vector<ModLoadErrorDetails> load_mods(const GameEntry& game_entry, const std::string& game_mode_id, uint8_t* rdram, int32_t load_address, uint32_t& ram_used);
void unload_mods(); void unload_mods();
@ -393,6 +404,7 @@ namespace recomp {
std::unordered_set<std::string> mod_ids; std::unordered_set<std::string> mod_ids;
std::unordered_set<std::string> enabled_mods; std::unordered_set<std::string> enabled_mods;
std::unordered_set<std::string> auto_enabled_mods; std::unordered_set<std::string> auto_enabled_mods;
std::unordered_map<std::string, DeprecationStatus> deprecated_mods;
std::unordered_map<recomp_func_t*, PatchData> patched_funcs; std::unordered_map<recomp_func_t*, PatchData> patched_funcs;
std::unordered_map<std::string, size_t> loaded_mods_by_id; std::unordered_map<std::string, size_t> loaded_mods_by_id;
std::unique_ptr<std::thread> mod_configuration_thread; std::unique_ptr<std::thread> mod_configuration_thread;
@ -597,7 +609,8 @@ namespace recomp {
CodeModLoadError validate_api_version(uint32_t api_version, std::string& error_param); CodeModLoadError validate_api_version(uint32_t api_version, std::string& error_param);
void initialize_mods(); void initialize_mods();
void register_embedded_mod(const std::string &mod_id, std::span<const uint8_t> mod_bytes); void register_embedded_mod(const std::string& mod_id, std::span<const uint8_t> mod_bytes);
void register_deprecated_mod(const std::string &mod_id, recomp::mods::DeprecationStatus deprecation_status);
void scan_mods(); void scan_mods();
void close_mods(); void close_mods();
std::filesystem::path get_mods_directory(); std::filesystem::path get_mods_directory();
@ -609,6 +622,9 @@ namespace recomp {
void enable_mod(const std::string& mod_id, bool enabled); void enable_mod(const std::string& mod_id, bool enabled);
bool is_mod_enabled(const std::string& mod_id); bool is_mod_enabled(const std::string& mod_id);
bool is_mod_auto_enabled(const std::string& mod_id); bool is_mod_auto_enabled(const std::string& mod_id);
bool is_mod_deprecated(const std::string& mod_id);
DeprecationStatus get_mod_deprecation_status(const std::string& mod_id);
std::string deprecation_status_to_message(DeprecationStatus deprecation_status);
const config::ConfigSchema &get_mod_config_schema(const std::string &mod_id); const config::ConfigSchema &get_mod_config_schema(const std::string &mod_id);
config::Config *get_mod_config(const std::string &mod_id); config::Config *get_mod_config(const std::string &mod_id);
const std::vector<char> &get_mod_thumbnail(const std::string &mod_id); const std::vector<char> &get_mod_thumbnail(const std::string &mod_id);

View file

@ -636,6 +636,10 @@ void recomp::mods::ModContext::register_embedded_mod(const std::string &mod_id,
embedded_mod_bytes.emplace(mod_id, mod_bytes); embedded_mod_bytes.emplace(mod_id, mod_bytes);
} }
void recomp::mods::ModContext::register_deprecated_mod(const std::string& mod_id, DeprecationStatus deprecation_status) {
deprecated_mods[mod_id] = deprecation_status;
}
void recomp::mods::ModContext::close_mods() { void recomp::mods::ModContext::close_mods() {
std::unique_lock lock(opened_mods_mutex); std::unique_lock lock(opened_mods_mutex);
opened_mods_by_id.clear(); opened_mods_by_id.clear();
@ -1037,6 +1041,11 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable
return; return;
} }
// Do nothing if this mod was deprecated.
if (is_mod_deprecated(mod_id)) {
return;
}
if (enabled) { if (enabled) {
bool was_enabled = enabled_mods.emplace(mod_id).second; bool was_enabled = enabled_mods.emplace(mod_id).second;
@ -1061,7 +1070,7 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable
if (mod_from_stack_it != opened_mods_by_id.end()) { if (mod_from_stack_it != opened_mods_by_id.end()) {
const ModHandle &mod_from_stack_handle = opened_mods[mod_from_stack_it->second]; const ModHandle &mod_from_stack_handle = opened_mods[mod_from_stack_it->second];
for (const Dependency &dependency : mod_from_stack_handle.manifest.dependencies) { for (const Dependency &dependency : mod_from_stack_handle.manifest.dependencies) {
if (!dependency.optional && !auto_enabled_mods.contains(dependency.mod_id)) { if (!dependency.optional && !auto_enabled_mods.contains(dependency.mod_id) && !is_mod_deprecated(dependency.mod_id)) {
auto_enabled_mods.emplace(dependency.mod_id); auto_enabled_mods.emplace(dependency.mod_id);
mod_stack.emplace_back(dependency.mod_id); mod_stack.emplace_back(dependency.mod_id);
@ -1106,7 +1115,7 @@ void recomp::mods::ModContext::enable_mod(const std::string& mod_id, bool enable
if (mod_from_stack_it != opened_mods_by_id.end()) { if (mod_from_stack_it != opened_mods_by_id.end()) {
const ModHandle &mod_from_stack_handle = opened_mods[mod_from_stack_it->second]; const ModHandle &mod_from_stack_handle = opened_mods[mod_from_stack_it->second];
for (const Dependency &dependency : mod_from_stack_handle.manifest.dependencies) { for (const Dependency &dependency : mod_from_stack_handle.manifest.dependencies) {
if (!dependency.optional && !new_auto_enabled_mods.contains(dependency.mod_id)) { if (!dependency.optional && !new_auto_enabled_mods.contains(dependency.mod_id) && !is_mod_deprecated(dependency.mod_id)) {
new_auto_enabled_mods.emplace(dependency.mod_id); new_auto_enabled_mods.emplace(dependency.mod_id);
mod_stack.emplace_back(dependency.mod_id); mod_stack.emplace_back(dependency.mod_id);
} }
@ -1150,6 +1159,20 @@ bool recomp::mods::ModContext::is_mod_auto_enabled(const std::string& mod_id) co
return auto_enabled_mods.contains(mod_id); return auto_enabled_mods.contains(mod_id);
} }
bool recomp::mods::ModContext::is_mod_deprecated(const std::string& mod_id) const {
return get_mod_deprecation_status(mod_id) != DeprecationStatus::Unknown;
}
recomp::mods::DeprecationStatus recomp::mods::ModContext::get_mod_deprecation_status(const std::string& mod_id) const {
auto it = deprecated_mods.find(mod_id);
if (it != deprecated_mods.end()) {
return it->second;
}
else {
return recomp::mods::DeprecationStatus::Unknown;
}
}
size_t recomp::mods::ModContext::num_opened_mods() { size_t recomp::mods::ModContext::num_opened_mods() {
return opened_mods.size(); return opened_mods.size();
} }

View file

@ -102,6 +102,11 @@ void recomp::mods::register_embedded_mod(const std::string &mod_id, std::span<co
mod_context->register_embedded_mod(mod_id, mod_bytes); mod_context->register_embedded_mod(mod_id, mod_bytes);
} }
void recomp::mods::register_deprecated_mod(const std::string& mod_id, recomp::mods::DeprecationStatus deprecation_status) {
std::lock_guard<std::mutex> lock(mod_context_mutex);
mod_context->register_deprecated_mod(mod_id, deprecation_status);
}
void recomp::mods::scan_mods() { void recomp::mods::scan_mods() {
std::vector<recomp::mods::ModOpenErrorDetails> mod_open_errors; std::vector<recomp::mods::ModOpenErrorDetails> mod_open_errors;
{ {
@ -570,6 +575,25 @@ bool recomp::mods::is_mod_auto_enabled(const std::string& mod_id) {
return mod_context->is_mod_auto_enabled(mod_id); return mod_context->is_mod_auto_enabled(mod_id);
} }
bool recomp::mods::is_mod_deprecated(const std::string& mod_id) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->is_mod_deprecated(mod_id);
}
recomp::mods::DeprecationStatus recomp::mods::get_mod_deprecation_status(const std::string& mod_id) {
std::lock_guard lock{ mod_context_mutex };
return mod_context->get_mod_deprecation_status(mod_id);
}
std::string recomp::mods::deprecation_status_to_message(DeprecationStatus deprecation_status) {
switch (deprecation_status) {
case DeprecationStatus::Integrated:
return "This mod has already been integrated into the game";
default:
return "Reason is unknown";
}
}
const recomp::config::ConfigSchema &recomp::mods::get_mod_config_schema(const std::string &mod_id) { const recomp::config::ConfigSchema &recomp::mods::get_mod_config_schema(const std::string &mod_id) {
std::lock_guard lock{ mod_context_mutex }; std::lock_guard lock{ mod_context_mutex };
return mod_context->get_mod_config_schema(mod_id); return mod_context->get_mod_config_schema(mod_id);