diff --git a/docs/CORE_LIBRARY.md b/docs/CORE_LIBRARY.md index c9321a4..13c654f 100644 --- a/docs/CORE_LIBRARY.md +++ b/docs/CORE_LIBRARY.md @@ -1,5 +1,10 @@ # Core titles in the library +The N64 internal-resolution menu offers 1x, 2x and 3x for every title, in both +platform and title settings. A previously saved or explicit higher numeric +scale is resolved to 3x when the hub launches N64. This shared player policy +does not change other systems' scales or the core's developer diagnostics. + A **core title** plays inside the hub's own window through an rcore core (Retro-Runtime `docs/CORE_LINK.md`), instead of being spawned as its own program. This page covers how such a title gets into the library and how Play reaches it. Linux only, diff --git a/src/hub/hub_core_settings.cpp b/src/hub/hub_core_settings.cpp index 1c2eaf5..856a746 100644 --- a/src/hub/hub_core_settings.cpp +++ b/src/hub/hub_core_settings.cpp @@ -12,6 +12,22 @@ namespace retcomm::hub { +std::string player_core_option_value(const std::string& platform, const std::string& key, + const std::string& value) { + if (platform != "n64" || key != "video.internal_resolution") return value; + const auto scale = [](const std::string& text) -> unsigned { + if (text.size() < 2 || text.back() != 'x') return 0; + unsigned result = 0; + for (std::size_t i = 0; i + 1 < text.size(); ++i) { + if (text[i] < '0' || text[i] > '9') return 0; + result = result * 10 + static_cast(text[i] - '0'); + if (result > 64) return 0; + } + return result; + }; + return scale(value) > 3 ? "3x" : value; +} + namespace { namespace corelink = ::retro::corelink; diff --git a/src/hub/hub_core_settings.hpp b/src/hub/hub_core_settings.hpp index 9df94e3..e13026f 100644 --- a/src/hub/hub_core_settings.hpp +++ b/src/hub/hub_core_settings.hpp @@ -50,6 +50,12 @@ struct CoreOptionDecl { std::string description; }; +// Shared player-facing limits apply to both the menu and launch options. +// N64 currently offers at most 3x; the core's diagnostic scales remain available +// to developer tools. Other platforms/options and non-scale values pass through. +std::string player_core_option_value(const std::string& platform, const std::string& key, + const std::string& value); + struct CoreInputDecl { std::uint32_t button = 0; // one RCORE_PAD_* bit, or 0 std::uint32_t axis = 0; // RCORE_AXIS_* + 1, or 0 diff --git a/src/hub/hub_main.cpp b/src/hub/hub_main.cpp index e3dc586..b75cb41 100644 --- a/src/hub/hub_main.cpp +++ b/src/hub/hub_main.cpp @@ -11120,6 +11120,8 @@ void apply_player_settings(retcomm::hub::PlayArgs& args, const fs::path& data_di drop(title, "this title's"); } args.options = retcomm::hub::layer_core_options(plat, title, args.options); + for (auto& [key, value] : args.options) + value = retcomm::hub::player_core_option_value(platform, key, value); } // A runner from before seats 2-4 took a Transfer Pak (no transfer_pak_seats @@ -11617,7 +11619,8 @@ void draw_core_option_row(CoreSettingsPage& p, const retcomm::hub::CoreOptionDec std::string inherited = o.has_default ? o.default_value : std::string(); if (p.title_scope) if (const auto it = p.plat_opts.find(o.key); it != p.plat_opts.end()) inherited = it->second; - const std::string cur = set ? own->second : inherited; + const std::string requested = set ? own->second : inherited; + const std::string cur = retcomm::hub::player_core_option_value(p.platform, o.key, requested); const std::string label = o.label.empty() ? o.key : o.label; const char* inherit_word = p.title_scope ? "All titles" : "Default"; @@ -11635,6 +11638,8 @@ void draw_core_option_row(CoreSettingsPage& p, const retcomm::hub::CoreOptionDec layer.erase(o.key); for (const std::string& v : o.values) { if (p.title_scope && v == kTitleDeclaredValue) continue; + if (retcomm::hub::player_core_option_value(p.platform, o.key, v) != v) + continue; const bool chosen = (set || p.title_scope) && v == cur; if (ImGui::Selectable(v.c_str(), chosen)) layer[o.key] = v; if (chosen) ImGui::SetItemDefaultFocus(); diff --git a/tests/hub_core_settings_test.cpp b/tests/hub_core_settings_test.cpp index c067fa5..14302e1 100644 --- a/tests/hub_core_settings_test.cpp +++ b/tests/hub_core_settings_test.cpp @@ -613,6 +613,17 @@ int main(int argc, char** argv) { test_display(dir); test_n64lle_mods(dir); test_n64lle_options(dir); + check(player_core_option_value("n64", "video.internal_resolution", "4x") == "3x", + "N64 stored or explicit 4x launches at 3x"); + check(player_core_option_value("n64", "video.internal_resolution", "6x") == "3x", + "N64 higher diagnostic scales are not player choices"); + for (const std::string& value : {"1x", "2x", "3x", "title", "bad", "99999999999999999x"}) + check(player_core_option_value("n64", "video.internal_resolution", value) == value, + "N64 lower scales and non-scale values pass through"); + check(player_core_option_value("psx", "video.internal_resolution", "4x") == "4x", + "other platforms retain their own scales"); + check(player_core_option_value("n64", "video.supersampling", "4x") == "4x", + "unrelated options retain their own choices"); test_transfer_pak(dir); test_tpak_library(dir); {