MONKEY (followups): re-apply the saved presets to rows missing from config

On load, Cvars::reapply_saved_presets writes the saved graphicsQuality rung (and the saved
lightingQuality rung, else the Graphics rung's) over every governed row the file does not carry,
so a row registered after the save follows the preset instead of its registered default. Rows the
file carries and session-owned rows stay; Custom writes nothing. Tests for both ladders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
pkuzic
2026-09-25 21:53:25 +01:00
co-authored by Claude Opus 5.5
parent 8fde660924
commit 40ebaec012
+162 -1
View File
@@ -1806,6 +1806,64 @@ impl Cvars {
moved
}
/// MONKEY (followups): **re-apply the saved presets to rows the file does not carry.** A saved
/// rung name implies every governed row matched it when the file was written (the label is
/// re-derived every frame), and a row at its registered default is not saved. So a governed
/// row ABSENT from the file is one that was registered after the save (or held a rung value
/// equal to its default): it takes the saved rung's value, not its own registered default.
/// Rows the file carries and session-owned rows are never touched; `Custom` (or no saved
/// name) writes nothing. The lighting rung is the file's own `lightingQuality`, or else the
/// saved Graphics rung's. Returns how many rows moved.
pub(crate) fn reapply_saved_presets(&mut self) -> usize {
let carried = |cvars: &Self, k: &str| {
cvars.file.keys().any(|f| f.eq_ignore_ascii_case(k)) || cvars.is_session_owned(k)
};
let saved = |cvars: &Self, k: &str| {
if cvars.is_session_owned(k) {
return None;
}
cvars
.file
.iter()
.find(|(f, _)| f.eq_ignore_ascii_case(k))
.map(|(_, v)| v.clone())
};
let mut moved = 0;
let col = saved(self, "graphicsQuality").and_then(|v| graphics_column(v.trim()));
if let Some(col) = col {
for (k, values) in GRAPHICS_PRESETS {
if k.eq_ignore_ascii_case("lightingQuality") || carried(self, k) {
continue;
}
if self.set(k, values[col]) == SetOutcome::Changed {
moved += 1;
}
}
}
let lighting = saved(self, "lightingQuality").or_else(|| {
let col = col?;
GRAPHICS_PRESETS
.iter()
.find(|(k, _)| k.eq_ignore_ascii_case("lightingQuality"))
.map(|(_, values)| values[col].to_string())
});
let members = lighting.and_then(|name| {
LIGHTING_PRESETS
.iter()
.find(|(n, _)| n.eq_ignore_ascii_case(name.trim()))
.map(|(_, members)| *members)
});
for (k, v) in members.unwrap_or(&[]) {
if carried(self, k) {
continue;
}
if self.set(k, v) == SetOutcome::Changed {
moved += 1;
}
}
moved
}
/// **The table follows a value the engine already applied** — a mirror, not a write: the
/// applied value moves, the config dirties, the VM's mirror learns it, and **no observer
/// fires**, because the knob is already there. For a second registered spelling of one knob
@@ -2501,7 +2559,11 @@ fn load_config(world: &mut World) {
// the file.
warn!("{msg}");
}
StoredConfig::Table(table) => cvars.load_file(table),
StoredConfig::Table(table) => {
cvars.load_file(table);
// MONKEY (followups): rows registered after the save follow the saved preset.
cvars.reapply_saved_presets();
}
}
// MONKEY (presets): a player's own run (never a capture, never a malformed file) boots
// into the default Graphics Preset over whatever its file leaves unsaid.
@@ -3552,6 +3614,105 @@ mod tests {
assert_eq!(again.get("graphicsQuality"), Some("High"));
}
/// MONKEY (followups): a saved Graphics rung fills the governed rows the file lacks (a row
/// registered after the save) with the rung's value; rows the file carries stay; Custom and
/// no saved name write nothing.
#[test]
fn a_saved_graphics_preset_fills_rows_missing_from_the_file() {
// An Ultra save made before `ambientOcclusion` / `lampFog` existed.
let file = BTreeMap::from([
("graphicsQuality".to_string(), "Ultra".to_string()),
("lightingQuality".to_string(), "Ultra".to_string()),
("farclip".to_string(), "1497".to_string()),
("zoneSkyboxes".to_string(), "0".to_string()), // the player's own later edit
]);
let mut cvars = fresh_registry();
cvars.load_file(file);
assert!(cvars.reapply_saved_presets() > 0);
assert_eq!(cvars.get("ambientOcclusion"), Some("2"));
assert_eq!(cvars.get("lampFog"), Some("2"));
assert_eq!(cvars.get("farclip"), Some("1497"));
assert_eq!(cvars.get("zoneSkyboxes"), Some("0"), "a saved row stays");
// The lighting members follow Ultra too.
assert_eq!(cvars.get("shadowMapSize"), Some("4096"));
assert_eq!(cvars.get("volumetricFog"), Some("2"));
// Medium without a saved lighting rung: the Graphics rung's lighting rung applies.
let mut medium = fresh_registry();
medium.load_file(BTreeMap::from([(
"graphicsQuality".to_string(),
"Medium".to_string(),
)]));
medium.reapply_saved_presets();
assert_eq!(medium.get("ambientOcclusion"), Some("1"));
assert_eq!(medium.get("farclip"), Some("477"));
lighting_quality(&mut medium);
assert_eq!(medium.get("lightingQuality"), Some("Medium"));
assert_eq!(medium.get("graphicsQuality"), Some("Medium"));
// Custom writes nothing; neither does a file with no preset name.
for file in [
BTreeMap::from([("graphicsQuality".to_string(), LIGHTING_CUSTOM.to_string())]),
BTreeMap::from([("skyQuality".to_string(), "1".to_string())]),
] {
let mut custom = fresh_registry();
custom.load_file(file);
assert_eq!(custom.reapply_saved_presets(), 0);
assert_eq!(
custom.get("ambientOcclusion"),
custom.default_of("ambientOcclusion")
);
}
// A session-owned row is left to the session.
let mut owned = fresh_registry();
owned.own_for_session("farclip", Some("500"));
owned.load_file(BTreeMap::from([(
"graphicsQuality".to_string(),
"Ultra".to_string(),
)]));
owned.reapply_saved_presets();
assert_eq!(owned.get("farclip"), Some("500"));
assert_eq!(owned.get("ambientOcclusion"), Some("2"));
}
/// MONKEY (followups): a saved Lighting Quality rung fills the lighting members the file
/// lacks; members the file carries stay; Custom writes nothing.
#[test]
fn a_saved_lighting_preset_fills_members_missing_from_the_file() {
let mut cvars = fresh_registry();
cvars.load_file(BTreeMap::from([
("lightingQuality".to_string(), "Ultra".to_string()),
("volumetricFog".to_string(), "1".to_string()),
]));
assert!(cvars.reapply_saved_presets() > 0);
assert_eq!(cvars.get("shadowMapSize"), Some("4096"));
assert_eq!(cvars.get("interiorShadowCasters"), Some("16"));
assert_eq!(cvars.get("volumetricFog"), Some("1"), "a saved member stays");
// No Graphics rung saved: the graphics rows keep their defaults.
assert_eq!(
cvars.get("ambientOcclusion"),
cvars.default_of("ambientOcclusion")
);
let mut off = fresh_registry();
off.load_file(BTreeMap::from([(
"lightingQuality".to_string(),
"Off".to_string(),
)]));
off.reapply_saved_presets();
assert_eq!(off.get("worldShadows"), Some("0"));
lighting_quality(&mut off);
assert_eq!(off.get("lightingQuality"), Some("Off"));
let mut custom = fresh_registry();
custom.load_file(BTreeMap::from([(
"lightingQuality".to_string(),
LIGHTING_CUSTOM.to_string(),
)]));
assert_eq!(custom.reapply_saved_presets(), 0);
}
/// The seed never overrides the player: a saved preset stops it outright, a saved row keeps
/// its value, and a session-owned row (an env lever) is left to the session.
#[test]