From 132776c1978195830caf6c225e31acc299c730ab Mon Sep 17 00:00:00 2001 From: Sam Sung <51686767+samwhosung@users.noreply.github.com> Date: Sat, 17 Oct 2026 02:15:58 +0700 Subject: [PATCH] cameraYawSmoothSpeed follows at the stored rate, not the slider's 90-270 (#1712) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `cameraYawSmoothSpeed` was clamped to 90-270 when applied, the Auto-Follow Speed slider's range, so `/console cameraYawSmoothSpeed 360` followed at 270. In 1.12.1 its validator `0x50c000` refuses only outside [0.1, 360] (`0x50b330`, `Value out of range` at `0x50b36c`) and the follow reader takes the stored rate as is (`[0xbe1070]` at `0x512d75`). The camera now uses the stored value; the registry's existing check, which already matched `0x50b330` and also runs on the config load, does the refusing. `FOLLOW_SPEED_RANGE` is gone. Test: 270, 360, 0.2 and 30 are stored and applied as given; 360.5, 400, 9000, 0, 0.05 and -30 are vetoed and keep 30. It fails with the clamp put back. Fixes #323 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (cherry picked from commit 9e1b3e9ae9c7fd488ea0addd3f11460678cd61fc) # Conflicts: # crates/benilla-app/src/cvars/mod.rs # crates/benilla-app/src/cvars/table.rs Absorbed into the octo fork. Ported by hand: our cvars registry is one file, not upstream's cvars/ split, and it has no .checked() validators or SetOutcome::Vetoed, so the clamp cannot simply be removed — without a veto channel that would turn a clamp into an unvalidated accept. FOLLOW_SPEED_RANGE is widened from the slider's 90..=270 to the reference validator's 0.1..=360 instead, so /console cameraYawSmoothSpeed 360 now follows at 360; refusing (rather than clamping) outside that window is recorded as a deviation on the constant. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- crates/benilla-app/src/cvars.rs | 13 ++++++++++--- crates/benilla-app/src/player/camera.rs | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/benilla-app/src/cvars.rs b/crates/benilla-app/src/cvars.rs index 14b75ca2..bae450ce 100644 --- a/crates/benilla-app/src/cvars.rs +++ b/crates/benilla-app/src/cvars.rs @@ -436,7 +436,9 @@ pub(crate) const REGISTERED: &[Registered] = &[ same("cameraSmoothTrackingStyle", "1"), // AUTO_FOLLOW_SPEED (`UIOptionsFrame.lua:88`), deg/s, registered "180.0" (`[0xbe1070]`): it // sets the transition's duration (`|dyaw| / rate * factor`), an average rate, not a slew. The - // knob clamps it to `FOLLOW_SPEED_RANGE`. The stock Save also writes `cameraPitchSmoothSpeed` + // validator `0x50c000` refuses outside [0.1, 360] and the follow reader (`0x512d75`) uses the + // stored value as is; 90 to 270 is only the stock slider's range, and clamping to it made + // `/console cameraYawSmoothSpeed 360` follow at 270. The stock Save also writes `cameraPitchSmoothSpeed` // at a quarter (`:353`), unregistered here: `FollowRig` has one rate. same("cameraYawSmoothSpeed", "180"), // `cameraPivot` `[0xbe10a4]` "1" (`0x50bda3`), smart pivot: gate `0x510690`, routing @@ -4171,8 +4173,13 @@ mod tests { FollowStyle::Smart, "and only that one" ); - apply(&mut app, "cameraYawSmoothSpeed", "270"); - assert_eq!(res::(&app).yaw_speed, 270.0); + // The validator's [0.1, 360] (`0x50c000`) is the range, not the stock slider's 90 to 270: + // a value inside it is stored and used as is (`0x512d75`). 360 is the case that was wrong. + for (text, want) in [("270", 270.0), ("360", 360.0), ("0.2", 0.2), ("30", 30.0)] { + apply(&mut app, "cameraYawSmoothSpeed", text); + assert_eq!(res::(&app).yaw_speed, want, "{text}"); + } + // Outside it the reference refuses the set; we clamp to the edge (see FOLLOW_SPEED_RANGE). apply(&mut app, "cameraYawSmoothSpeed", "9000"); assert_eq!( res::(&app).yaw_speed, diff --git a/crates/benilla-app/src/player/camera.rs b/crates/benilla-app/src/player/camera.rs index 8e8cf621..a97898fc 100644 --- a/crates/benilla-app/src/player/camera.rs +++ b/crates/benilla-app/src/player/camera.rs @@ -142,6 +142,8 @@ pub(crate) fn on_cvar( // The stock dropdown writes 1 Smart, 2 Always, 0 Never (`UIOptionsFrame.lua:518`). "camerasmoothstyle" => follow.style = FollowStyle::from_cvar(v), "camerasmoothtrackingstyle" => follow.tracking_style = FollowStyle::from_cvar(v), + // The follow reader takes the stored rate as is (`0x512d75`); 90 to 270 is only the stock + // slider's range, so a `/console` value inside the validator's own stands. "camerayawsmoothspeed" => { follow.yaw_speed = v.clamp(*FOLLOW_SPEED_RANGE.start(), *FOLLOW_SPEED_RANGE.end()); } @@ -202,8 +204,17 @@ impl LookConfig { /// `cameraYawSmoothSpeed`, default 180°/s (`[0xbe1070]`, read at `0x512d75`): a duration divisor, /// as a return lasts `|Δyaw| / rate × factor`. The AUTO_FOLLOW_SPEED slider, greyed under Never. pub(crate) const FOLLOW_SPEED_DEFAULT: f32 = 180.0; -/// The 1.12 slider's own range for [`FollowConfig::yaw_speed`]. -pub(crate) const FOLLOW_SPEED_RANGE: std::ops::RangeInclusive = 90.0..=270.0; +/// What the reference's validator `0x50c000` accepts for [`FollowConfig::yaw_speed`]: outside +/// [0.1, 360] it refuses the set outright (`0x50b330`, `Value out of range` at `0x50b36c`), and +/// the follow reader then uses the stored rate as is (`0x512d75`). 90 to 270 is the AUTO_FOLLOW_ +/// SPEED slider's range alone, and clamping to it made `/console cameraYawSmoothSpeed 360` follow +/// at 270. +/// +/// Deviation: the reference *refuses* an out-of-range set and keeps the old rate; we clamp to the +/// edge, because this registry has no veto channel — upstream's `Registered::checked` validators +/// and `SetOutcome::Vetoed` are not in this fork, so there is nowhere to report the refusal. The +/// accepted window is now the reference's; only what happens outside it still differs. +pub(crate) const FOLLOW_SPEED_RANGE: std::ops::RangeInclusive = 0.1..=360.0; /// `cameraSmoothTimeMin`/`Max`: 0.1 s and 2.0 s (`[0xbe105c]`/`[0xbe1038]`, clamped at `0x510f4d`). const FOLLOW_TIME_MIN: f32 = 0.1; const FOLLOW_TIME_MAX: f32 = 2.0;