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;