Add special config option id to control texture pack state for code mods

This commit is contained in:
Mr-Wiseguy 2025-04-09 03:51:26 -04:00
parent 8382fa3d65
commit 7407bebf6e
7 changed files with 162 additions and 21 deletions

View file

@ -14,6 +14,8 @@ namespace RT64 {
namespace zelda64 {
namespace renderer {
inline const std::string special_option_texture_pack_enabled = "_recomp_texture_pack_enabled";
class RT64Context final : public ultramodern::renderer::RendererContext {
public:
~RT64Context() override;
@ -33,6 +35,7 @@ namespace zelda64 {
private:
std::unique_ptr<RT64::Application> app;
std::unordered_set<std::string> enabled_texture_packs;
std::unordered_set<std::string> secondary_disabled_texture_packs;
void check_texture_pack_actions();
};
@ -44,8 +47,14 @@ namespace zelda64 {
bool RT64HighPrecisionFBEnabled();
void trigger_texture_pack_update();
void enable_texture_pack(const recomp::mods::ModHandle& mod);
void enable_texture_pack(const recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod);
void disable_texture_pack(const recomp::mods::ModHandle& mod);
void secondary_enable_texture_pack(const std::string& mod_id);
void secondary_disable_texture_pack(const std::string& mod_id);
// Texture pack enable option. Must be an enum with two options.
// The first option is treated as disabled and the second option is treated as enabled.
bool is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors);
}
}

@ -1 +1 @@
Subproject commit bb6b3b1645a582b8d9305f221375da9d3563ee60
Subproject commit 234ed4a95e6578c42434bc45d5232466a9b74de7

View file

@ -544,8 +544,8 @@ void release_preload(PreloadContext& context) {
#endif
void enable_texture_pack(recomp::mods::ModContext&, const recomp::mods::ModHandle& mod) {
zelda64::renderer::enable_texture_pack(mod);
void enable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) {
zelda64::renderer::enable_texture_pack(context, mod);
}
void disable_texture_pack(recomp::mods::ModContext&, const recomp::mods::ModHandle& mod) {

View file

@ -30,10 +30,18 @@ struct TexturePackDisableAction {
std::string mod_id;
};
struct TexturePackSecondaryEnableAction {
std::string mod_id;
};
struct TexturePackSecondaryDisableAction {
std::string mod_id;
};
struct TexturePackUpdateAction {
};
using TexturePackAction = std::variant<TexturePackEnableAction, TexturePackDisableAction, TexturePackUpdateAction>;
using TexturePackAction = std::variant<TexturePackEnableAction, TexturePackDisableAction, TexturePackSecondaryEnableAction, TexturePackSecondaryDisableAction, TexturePackUpdateAction>;
static moodycamel::ConcurrentQueue<TexturePackAction> texture_pack_action_queue;
@ -403,6 +411,14 @@ void zelda64::renderer::RT64Context::check_texture_pack_actions() {
enabled_texture_packs.insert(to_enable.mod_id);
packs_changed = true;
},
[&](TexturePackSecondaryDisableAction &to_override_disable) {
secondary_disabled_texture_packs.insert(to_override_disable.mod_id);
packs_changed = true;
},
[&](TexturePackSecondaryEnableAction &to_override_enable) {
secondary_disabled_texture_packs.erase(to_override_enable.mod_id);
packs_changed = true;
},
[&](TexturePackUpdateAction &) {
packs_changed = true;
}
@ -411,23 +427,29 @@ void zelda64::renderer::RT64Context::check_texture_pack_actions() {
// If any packs were disabled, unload all packs and load all the active ones.
if (packs_changed) {
if (!enabled_texture_packs.empty()) {
// Sort the enabled texture packs in reverse order so that earlier ones override later ones.
std::vector<std::string> sorted_texture_packs{};
sorted_texture_packs.assign(enabled_texture_packs.begin(), enabled_texture_packs.end());
std::sort(sorted_texture_packs.begin(), sorted_texture_packs.end(),
[](const std::string& lhs, const std::string& rhs) {
return recomp::mods::get_mod_order_index(lhs) > recomp::mods::get_mod_order_index(rhs);
}
);
// Build the path list from the sorted mod list.
std::vector<RT64::ReplacementDirectory> replacement_directories;
replacement_directories.reserve(enabled_texture_packs.size());
for (const std::string &mod_id : sorted_texture_packs) {
replacement_directories.emplace_back(RT64::ReplacementDirectory(recomp::mods::get_mod_filename(mod_id)));
// Sort the enabled texture packs in reverse order so that earlier ones override later ones.
std::vector<std::string> sorted_texture_packs{};
sorted_texture_packs.reserve(enabled_texture_packs.size());
for (const std::string& mod : enabled_texture_packs) {
if (!secondary_disabled_texture_packs.contains(mod)) {
sorted_texture_packs.emplace_back(mod);
}
}
std::sort(sorted_texture_packs.begin(), sorted_texture_packs.end(),
[](const std::string& lhs, const std::string& rhs) {
return recomp::mods::get_mod_order_index(lhs) > recomp::mods::get_mod_order_index(rhs);
}
);
// Build the path list from the sorted mod list.
std::vector<RT64::ReplacementDirectory> replacement_directories;
replacement_directories.reserve(enabled_texture_packs.size());
for (const std::string &mod_id : sorted_texture_packs) {
replacement_directories.emplace_back(RT64::ReplacementDirectory(recomp::mods::get_mod_filename(mod_id)));
}
if (!replacement_directories.empty()) {
app->textureCache->loadReplacementDirectories(replacement_directories);
}
else {
@ -456,10 +478,68 @@ void zelda64::renderer::trigger_texture_pack_update() {
texture_pack_action_queue.enqueue(TexturePackUpdateAction{});
}
void zelda64::renderer::enable_texture_pack(const recomp::mods::ModHandle& mod) {
void zelda64::renderer::enable_texture_pack(const recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) {
texture_pack_action_queue.enqueue(TexturePackEnableAction{mod.manifest.mod_id});
// Check for the texture pack enabled config option.
const recomp::mods::ConfigSchema& config_schema = context.get_mod_config_schema(mod.manifest.mod_id);
auto find_it = config_schema.options_by_id.find(zelda64::renderer::special_option_texture_pack_enabled);
if (find_it != config_schema.options_by_id.end()) {
const recomp::mods::ConfigOption& config_option = config_schema.options[find_it->second];
if (is_texture_pack_enable_config_option(config_option, false)) {
recomp::mods::ConfigValueVariant value_variant = context.get_mod_config_value(mod.manifest.mod_id, config_option.id);
uint32_t value;
if (uint32_t* value_ptr = std::get_if<uint32_t>(&value_variant)) {
value = *value_ptr;
}
else {
value = 0;
}
if (value) {
zelda64::renderer::secondary_enable_texture_pack(mod.manifest.mod_id);
}
else {
zelda64::renderer::secondary_disable_texture_pack(mod.manifest.mod_id);
}
}
}
}
void zelda64::renderer::disable_texture_pack(const recomp::mods::ModHandle& mod) {
texture_pack_action_queue.enqueue(TexturePackDisableAction{mod.manifest.mod_id});
}
void zelda64::renderer::secondary_enable_texture_pack(const std::string& mod_id) {
texture_pack_action_queue.enqueue(TexturePackSecondaryEnableAction{mod_id});
}
void zelda64::renderer::secondary_disable_texture_pack(const std::string& mod_id) {
texture_pack_action_queue.enqueue(TexturePackSecondaryDisableAction{mod_id});
}
// HD texture enable option. Must be an enum with two options.
// The first option is treated as disabled and the second option is treated as enabled.
bool zelda64::renderer::is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors) {
if (option.id == zelda64::renderer::special_option_texture_pack_enabled) {
if (option.type != recomp::mods::ConfigOptionType::Enum) {
if (show_errors) {
recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + zelda64::renderer::special_option_texture_pack_enabled + "\"), but the config option is not an enum.").c_str());
}
return false;
}
const recomp::mods::ConfigOptionEnum &option_enum = std::get<recomp::mods::ConfigOptionEnum>(option.variant);
if (option_enum.options.size() != 2) {
if (show_errors) {
recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + zelda64::renderer::special_option_texture_pack_enabled + "\"), but the config option doesn't have exactly 2 values.").c_str());
}
return false;
}
return true;
}
return false;
}

View file

@ -1,6 +1,7 @@
#include "ui_mod_menu.h"
#include "recomp_ui.h"
#include "zelda_support.h"
#include "zelda_render.h"
#include "librecomp/mods.hpp"
@ -384,6 +385,22 @@ ContextId get_config_sub_menu_context_id() {
return sub_menu_context;
}
bool ModMenu::handle_special_config_options(const recomp::mods::ConfigOption& option, const recomp::mods::ConfigValueVariant& config_value) {
if (zelda64::renderer::is_texture_pack_enable_config_option(option, true)) {
const recomp::mods::ConfigOptionEnum &option_enum = std::get<recomp::mods::ConfigOptionEnum>(option.variant);
config_sub_menu->add_radio_option(option.id, option.name, option.description, std::get<uint32_t>(config_value), option_enum.options,
[this](const std::string &id, uint32_t value) {
mod_enum_option_changed(id, value);
mod_hd_textures_enabled_changed(value);
});
return true;
}
return false;
}
void ModMenu::mod_configure_requested() {
if (active_mod_index >= 0) {
// Record the context that was open when this function was called and close it.
@ -401,6 +418,10 @@ void ModMenu::mod_configure_requested() {
continue;
}
if (handle_special_config_options(option, config_value)) {
continue;
}
switch (option.type) {
case recomp::mods::ConfigOptionType::Enum: {
const recomp::mods::ConfigOptionEnum &option_enum = std::get<recomp::mods::ConfigOptionEnum>(option.variant);
@ -455,6 +476,17 @@ void ModMenu::mod_number_option_changed(const std::string &id, double value) {
}
}
void ModMenu::mod_hd_textures_enabled_changed(uint32_t value) {
if (active_mod_index >= 0) {
if (value) {
zelda64::renderer::secondary_enable_texture_pack(mod_details[active_mod_index].mod_id);
}
else {
zelda64::renderer::secondary_disable_texture_pack(mod_details[active_mod_index].mod_id);
}
}
}
void ModMenu::create_mod_list() {
ContextId context = get_current_context();

View file

@ -74,9 +74,11 @@ private:
void mod_selected(uint32_t mod_index);
void mod_dragged(uint32_t mod_index, EventDrag drag);
void mod_configure_requested();
bool handle_special_config_options(const recomp::mods::ConfigOption& option, const recomp::mods::ConfigValueVariant& config_value);
void mod_enum_option_changed(const std::string &id, uint32_t value);
void mod_string_option_changed(const std::string &id, const std::string &value);
void mod_number_option_changed(const std::string &id, double value);
void mod_hd_textures_enabled_changed(uint32_t value);
void create_mod_list();
void process_event(const Event &e) override;

View file

@ -234,6 +234,8 @@ void recompui::open_choice_prompt(
std::function<void()> prev_cancel_action = std::move(prompt_state.cancel_action);
ContextId prev_context = try_close_current_context();
prompt_state.ui_context.open();
prompt_state.prompt_header->set_text(header_text);
@ -252,6 +254,10 @@ void recompui::open_choice_prompt(
prompt_state.ui_context.close();
if (prev_context != ContextId::null()) {
prev_context.open();
}
show_prompt(prev_cancel_action, focus_on_cancel);
}
@ -267,6 +273,8 @@ void recompui::open_info_prompt(
std::function<void()> prev_cancel_action = std::move(prompt_state.cancel_action);
ContextId prev_context = try_close_current_context();
prompt_state.ui_context.open();
prompt_state.prompt_header->set_text(header_text);
@ -283,6 +291,10 @@ void recompui::open_info_prompt(
prompt_state.ui_context.close();
if (prev_context != ContextId::null()) {
prev_context.open();
}
show_prompt(prev_cancel_action, true);
}
@ -295,6 +307,8 @@ void recompui::open_notification(
std::function<void()> prev_cancel_action = std::move(prompt_state.cancel_action);
ContextId prev_context = try_close_current_context();
prompt_state.ui_context.open();
prompt_state.prompt_header->set_text(header_text);
@ -308,6 +322,10 @@ void recompui::open_notification(
prompt_state.ui_context.close();
if (prev_context != ContextId::null()) {
prev_context.open();
}
show_prompt(prev_cancel_action, false);
}