From a32471d5fdc91ea390a12006eee145dfa650af44 Mon Sep 17 00:00:00 2001 From: Shokunin <30949000+tetrisgm@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:03:21 -0700 Subject: [PATCH] Live mod options: restart-only changes do not reach the running plugin Co-Authored-By: Claude Opus 5.5 --- runtime/include/mod_plugins.h | 5 +++-- runtime/src/mod_runtime.cpp | 4 +++- runtime/tests/test_mod_runtime.cpp | 11 +++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/runtime/include/mod_plugins.h b/runtime/include/mod_plugins.h index 78515797..ef0f345a 100644 --- a/runtime/include/mod_plugins.h +++ b/runtime/include/mod_plugins.h @@ -380,8 +380,9 @@ int psx_mod_current_option_value(const char* option_id, * * psx_mod_set_option_live records a new value for a committed feature's * option for the rest of the session and notifies its plugin. Returns 1 when - * a plugin applied it live, 0 when it only takes effect after a restart (or - * the feature is not in the plan), -1 when refused: during netplay the plan is + * a plugin applied it live; 0 when the feature has no live-capable plugin (or + * is not in the plan) -- then nothing changes until the next start; -1 when + * refused: during netplay the plan is * negotiated between peers and must not change. Persisting the choice stays * the mod provider's job (mods/state.toml). */ diff --git a/runtime/src/mod_runtime.cpp b/runtime/src/mod_runtime.cpp index 9f4d3bc7..be4295f7 100644 --- a/runtime/src/mod_runtime.cpp +++ b/runtime/src/mod_runtime.cpp @@ -2868,7 +2868,9 @@ extern "C" int psx_mod_set_option_live(const char* package_id, const char* featu bool in_plan = false; for (const ModResolution::Plugin& plugin : s.plan.plugins) if (plugin.package_id == package_id && plugin.feature_id == feature_id) in_plan = true; - if (!in_plan) return 0; + if (!in_plan || !psx_mod_option_live_capable(package_id, feature_id)) return 0; + /* Only a feature whose plugin re-reads options live sees the new value; + * anything else keeps its committed value until the next start. */ live_option_values()[live_option_key(package_id, feature_id, option_id)] = value; int live = 0; for (const ModResolution::Plugin& plugin : s.plan.plugins) { diff --git a/runtime/tests/test_mod_runtime.cpp b/runtime/tests/test_mod_runtime.cpp index d9dc46bb..3d4d62d6 100644 --- a/runtime/tests/test_mod_runtime.cpp +++ b/runtime/tests/test_mod_runtime.cpp @@ -1099,17 +1099,20 @@ int main(int argc, char** argv) { check(psx_mod_set_option_live("runtime.ram", "big-ram", "size", "four") == 0, "without an option-changed callback a live set waits for restart"); check(psx_mod_option_value("runtime.ram", "big-ram", "size", value, sizeof(value)) == 1 && - std::string(value) == "four", - "a live override must answer later reads"); + std::string(value) == "eight", + "a restart-only change must not reach the running plugin"); check(!psx_mod_option_live_capable("runtime.ram", "big-ram"), "no callback yet: not live-capable"); check(psx_mod_register_option_changed_plugin("runtime.big-ram", test_option_changed), "option-changed hook must register"); check(psx_mod_option_live_capable("runtime.ram", "big-ram"), "a registered callback makes the feature live-capable"); - check(psx_mod_set_option_live("runtime.ram", "big-ram", "size", "eight") == 1 && - option_changed_hits == 1 && option_changed_value == "eight", + check(psx_mod_set_option_live("runtime.ram", "big-ram", "size", "four") == 1 && + option_changed_hits == 1 && option_changed_value == "four", "the plugin must see the change in its own context"); + check(psx_mod_option_value("runtime.ram", "big-ram", "size", value, sizeof(value)) == 1 && + std::string(value) == "four", + "a live override must answer later reads"); check(psx_mod_set_option_live("runtime.ram", "no-such-feature", "size", "x") == 0, "features outside the plan are not live-settable"); test_netplay_active = 1;