feat: v2.0 premium physics — yaw damping, slip discrimination, adaptive smooth, TC#3
Conversation
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Review limit reached
More reviews will be available in 44 minutes and 25 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughMyGamepadFX is upgraded from v1.0 to v2.0. Five new pipeline stage functions are added to ChangesMyGamepadFX v2.0 Multi-Stage Control Pipeline
Sequence Diagram(s)sequenceDiagram
participant Game as AC Game Loop
participant Assist as assist.lua (script.update)
participant Lib as lib.lua
participant AC as ac (physics output)
rect rgba(100, 149, 237, 0.5)
note over Assist,Lib: Slip & Yaw Classification
Assist->>Lib: stageSlipClassify(car, cfg) → frontSlip, rearSlip, stability, overFactor
Assist->>Lib: yawRate(car) → yaw
Assist->>Lib: stageYawDamp(yaw, steerAngle, cfg, overFactor, damp) → yawCorrection
end
rect rgba(144, 238, 144, 0.5)
note over Assist,Lib: Smoothing & Output
Assist->>Lib: stageAdaptiveSmooth(current, target, stability, cfg, dt) → steerOut
Assist->>Lib: stageWheelspin(car) → spinRatio
Assist->>AC: setSteer(clamp(steerOut))
Assist->>AC: setGas(gas × (1 − TC_reduction))
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Quality Check ✅ Passed
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@MyGamepadFX_Config/app.lua`:
- Around line 108-126: After loading STEER_SMOOTH_MIN from the ini file in this
configuration load section, add validation to ensure that STEER_SMOOTH_MIN does
not exceed STEER_SMOOTH. If STEER_SMOOTH_MIN is greater than STEER_SMOOTH, clamp
it to the STEER_SMOOTH value to prevent adaptive smoothing from working
backwards. Apply the same validation constraint in the UI path around lines
166-169 where STEER_SMOOTH_MIN is also handled to maintain consistency between
the load and UI paths.
In `@MyGamepadFX/assist.lua`:
- Around line 31-49: In the applyLiveCfg() function, the numeric values
retrieved from ini:get() for parameters like SLIP_DELTA_THRESH,
SLIP_LIMIT_RANGE, and other divisor-dependent values are assigned directly to
CFG without validation, which can cause Inf/NaN results when these values are
used in division operations at line 109 and in MyGamepadFX/lib.lua line 84. Add
clamping logic after each ini:get() call to ensure critical numeric parameters
that are used as divisors (such as SLIP_DELTA_THRESH and SLIP_LIMIT_RANGE) have
minimum values greater than 0, and ensure other numeric parameters are within
acceptable ranges before assigning them to their corresponding CFG properties.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: d12a54f1-f194-4355-8057-67b2116de724
📒 Files selected for processing (6)
MyGamepadFX/assist.luaMyGamepadFX/config.luaMyGamepadFX/lib.luaMyGamepadFX/manifest.iniMyGamepadFX_Config/app.luaMyGamepadFX_Config/manifest.ini
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.lua
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.lua: Do not make pre-build calls or load packages; Lua files must run directly in LuaJIT 5.2 compatibility mode via Custom Shaders Patch with no build system
Always nil-guard before reading car properties from ac.getCar(0) as it returns nil on the first frame; also guard against dt <= 0
Use expSmooth with (1 - smooth)^(dt * 60) formula for frame-rate independence instead of bare lerp constants directly against dt
Files:
MyGamepadFX/config.luaMyGamepadFX_Config/app.luaMyGamepadFX/lib.luaMyGamepadFX/assist.lua
🔇 Additional comments (4)
MyGamepadFX/lib.lua (1)
67-111: LGTM!MyGamepadFX/config.lua (1)
4-4: LGTM!Also applies to: 17-32, 45-57
MyGamepadFX/manifest.ini (1)
3-3: LGTM!MyGamepadFX_Config/manifest.ini (1)
4-4: LGTM!Also applies to: 10-10
| cfg.STEER_SMOOTH_MIN = ini:get('PARAMS', 'STEER_SMOOTH_MIN', cfg.STEER_SMOOTH_MIN) | ||
| cfg.SPEED_SCALE_START = ini:get('PARAMS', 'SPEED_SCALE_START', cfg.SPEED_SCALE_START) | ||
| cfg.SPEED_SCALE_END = ini:get('PARAMS', 'SPEED_SCALE_END', cfg.SPEED_SCALE_END) | ||
| cfg.SPEED_SCALE_MIN = ini:get('PARAMS', 'SPEED_SCALE_MIN', cfg.SPEED_SCALE_MIN) | ||
| cfg.COUNTERSTEER_GAIN = ini:get('PARAMS', 'COUNTERSTEER_GAIN', cfg.COUNTERSTEER_GAIN) | ||
| cfg.COUNTERSTEER_DAMP = ini:get('PARAMS', 'COUNTERSTEER_DAMP', cfg.COUNTERSTEER_DAMP) | ||
| cfg.YAW_GAIN = ini:get('PARAMS', 'YAW_GAIN', cfg.YAW_GAIN) | ||
| cfg.YAW_DAMP = ini:get('PARAMS', 'YAW_DAMP', cfg.YAW_DAMP) | ||
| cfg.SLIP_DELTA_THRESH = ini:get('PARAMS', 'SLIP_DELTA_THRESH', cfg.SLIP_DELTA_THRESH) | ||
| cfg.US_REDUCTION = ini:get('PARAMS', 'US_REDUCTION', cfg.US_REDUCTION) | ||
| cfg.OS_BOOST = ini:get('PARAMS', 'OS_BOOST', cfg.OS_BOOST) | ||
| cfg.SLIP_LIMIT_START = ini:get('PARAMS', 'SLIP_LIMIT_START', cfg.SLIP_LIMIT_START) | ||
| cfg.SLIP_LIMIT_RANGE = ini:get('PARAMS', 'SLIP_LIMIT_RANGE', cfg.SLIP_LIMIT_RANGE) | ||
| cfg.SLIP_LIMIT_MIN = ini:get('PARAMS', 'SLIP_LIMIT_MIN', cfg.SLIP_LIMIT_MIN) | ||
| cfg.GAS_DEADZONE = ini:get('PARAMS', 'GAS_DEADZONE', cfg.GAS_DEADZONE) | ||
| cfg.GAS_GAMMA = ini:get('PARAMS', 'GAS_GAMMA', cfg.GAS_GAMMA) | ||
| cfg.BRAKE_DEADZONE = ini:get('PARAMS', 'BRAKE_DEADZONE', cfg.BRAKE_DEADZONE) | ||
| cfg.BRAKE_GAMMA = ini:get('PARAMS', 'BRAKE_GAMMA', cfg.BRAKE_GAMMA) | ||
| cfg.TC_ENABLED = ini:get('PARAMS', 'TC_ENABLED', cfg.TC_ENABLED) | ||
| cfg.TC_SLIP_THRESHOLD = ini:get('PARAMS', 'TC_SLIP_THRESHOLD', cfg.TC_SLIP_THRESHOLD) | ||
| cfg.TC_MAX_REDUCTION = ini:get('PARAMS', 'TC_MAX_REDUCTION', cfg.TC_MAX_REDUCTION) |
There was a problem hiding this comment.
Enforce STEER_SMOOTH_MIN <= STEER_SMOOTH in load and UI paths.
If STEER_SMOOTH_MIN exceeds STEER_SMOOTH, adaptive smoothing works backwards (more smoothing under instability), which contradicts the v2 dynamics intent.
Proposed fix
- cfg.STEER_SMOOTH = ini:get('PARAMS', 'STEER_SMOOTH', cfg.STEER_SMOOTH)
- cfg.STEER_SMOOTH_MIN = ini:get('PARAMS', 'STEER_SMOOTH_MIN', cfg.STEER_SMOOTH_MIN)
+ cfg.STEER_SMOOTH = math.clamp(tonumber(ini:get('PARAMS', 'STEER_SMOOTH', cfg.STEER_SMOOTH)) or cfg.STEER_SMOOTH, 0.01, 0.50)
+ cfg.STEER_SMOOTH_MIN = math.min(
+ math.clamp(tonumber(ini:get('PARAMS', 'STEER_SMOOTH_MIN', cfg.STEER_SMOOTH_MIN)) or cfg.STEER_SMOOTH_MIN, 0.01, 0.20),
+ cfg.STEER_SMOOTH
+ )
@@
- sliderRow('Smooth min', 'STEER_SMOOTH_MIN', 0.01, 0.20, '%.2f')
+ sliderRow('Smooth min', 'STEER_SMOOTH_MIN', 0.01, math.min(0.20, cfg.STEER_SMOOTH), '%.2f')Also applies to: 166-169
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@MyGamepadFX_Config/app.lua` around lines 108 - 126, After loading
STEER_SMOOTH_MIN from the ini file in this configuration load section, add
validation to ensure that STEER_SMOOTH_MIN does not exceed STEER_SMOOTH. If
STEER_SMOOTH_MIN is greater than STEER_SMOOTH, clamp it to the STEER_SMOOTH
value to prevent adaptive smoothing from working backwards. Apply the same
validation constraint in the UI path around lines 166-169 where STEER_SMOOTH_MIN
is also handled to maintain consistency between the load and UI paths.
| CFG.STEER_SMOOTH_MIN = ini:get('PARAMS', 'STEER_SMOOTH_MIN', CFG.STEER_SMOOTH_MIN) | ||
| CFG.SPEED_SCALE_START = ini:get('PARAMS', 'SPEED_SCALE_START', CFG.SPEED_SCALE_START) | ||
| CFG.SPEED_SCALE_END = ini:get('PARAMS', 'SPEED_SCALE_END', CFG.SPEED_SCALE_END) | ||
| CFG.SPEED_SCALE_MIN = ini:get('PARAMS', 'SPEED_SCALE_MIN', CFG.SPEED_SCALE_MIN) | ||
| CFG.COUNTERSTEER_GAIN = ini:get('PARAMS', 'COUNTERSTEER_GAIN', CFG.COUNTERSTEER_GAIN) | ||
| CFG.COUNTERSTEER_DAMP = ini:get('PARAMS', 'COUNTERSTEER_DAMP', CFG.COUNTERSTEER_DAMP) | ||
| CFG.YAW_GAIN = ini:get('PARAMS', 'YAW_GAIN', CFG.YAW_GAIN) | ||
| CFG.YAW_DAMP = ini:get('PARAMS', 'YAW_DAMP', CFG.YAW_DAMP) | ||
| CFG.SLIP_DELTA_THRESH = ini:get('PARAMS', 'SLIP_DELTA_THRESH', CFG.SLIP_DELTA_THRESH) | ||
| CFG.US_REDUCTION = ini:get('PARAMS', 'US_REDUCTION', CFG.US_REDUCTION) | ||
| CFG.OS_BOOST = ini:get('PARAMS', 'OS_BOOST', CFG.OS_BOOST) | ||
| CFG.SLIP_LIMIT_START = ini:get('PARAMS', 'SLIP_LIMIT_START', CFG.SLIP_LIMIT_START) | ||
| CFG.SLIP_LIMIT_RANGE = ini:get('PARAMS', 'SLIP_LIMIT_RANGE', CFG.SLIP_LIMIT_RANGE) | ||
| CFG.SLIP_LIMIT_MIN = ini:get('PARAMS', 'SLIP_LIMIT_MIN', CFG.SLIP_LIMIT_MIN) | ||
| CFG.GAS_DEADZONE = ini:get('PARAMS', 'GAS_DEADZONE', CFG.GAS_DEADZONE) | ||
| CFG.GAS_GAMMA = ini:get('PARAMS', 'GAS_GAMMA', CFG.GAS_GAMMA) | ||
| CFG.BRAKE_DEADZONE = ini:get('PARAMS', 'BRAKE_DEADZONE', CFG.BRAKE_DEADZONE) | ||
| CFG.BRAKE_GAMMA = ini:get('PARAMS', 'BRAKE_GAMMA', CFG.BRAKE_GAMMA) | ||
| CFG.TC_ENABLED = ini:get('PARAMS', 'TC_ENABLED', CFG.TC_ENABLED) | ||
| CFG.TC_SLIP_THRESHOLD = ini:get('PARAMS', 'TC_SLIP_THRESHOLD', CFG.TC_SLIP_THRESHOLD) | ||
| CFG.TC_MAX_REDUCTION = ini:get('PARAMS', 'TC_MAX_REDUCTION', CFG.TC_MAX_REDUCTION) |
There was a problem hiding this comment.
Clamp live INI numeric values before assigning to CFG.
applyLiveCfg() trusts live_cfg.ini values. Invalid values (for example SLIP_DELTA_THRESH <= 0 or SLIP_LIMIT_RANGE <= 0) flow into divisions at Line 109 in this file and MyGamepadFX/lib.lua Line 84, producing unstable control math (Inf/NaN paths).
Proposed fix
local function applyLiveCfg()
local ok, ini = pcall(ac.INIConfig.load, LIVE_CFG_PATH)
if not ok or not ini then return end
+ local function getNum(key, fallback, minV, maxV)
+ local v = tonumber(ini:get('PARAMS', key, fallback)) or fallback
+ if minV and maxV then return math.clamp(v, minV, maxV) end
+ if minV then return math.max(v, minV) end
+ if maxV then return math.min(v, maxV) end
+ return v
+ end
@@
- CFG.SLIP_DELTA_THRESH = ini:get('PARAMS', 'SLIP_DELTA_THRESH', CFG.SLIP_DELTA_THRESH)
+ CFG.SLIP_DELTA_THRESH = getNum('SLIP_DELTA_THRESH', CFG.SLIP_DELTA_THRESH, 0.001, 1.0)
@@
- CFG.SLIP_LIMIT_RANGE = ini:get('PARAMS', 'SLIP_LIMIT_RANGE', CFG.SLIP_LIMIT_RANGE)
+ CFG.SLIP_LIMIT_RANGE = getNum('SLIP_LIMIT_RANGE', CFG.SLIP_LIMIT_RANGE, 0.001, 1.0)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@MyGamepadFX/assist.lua` around lines 31 - 49, In the applyLiveCfg() function,
the numeric values retrieved from ini:get() for parameters like
SLIP_DELTA_THRESH, SLIP_LIMIT_RANGE, and other divisor-dependent values are
assigned directly to CFG without validation, which can cause Inf/NaN results
when these values are used in division operations at line 109 and in
MyGamepadFX/lib.lua line 84. Add clamping logic after each ini:get() call to
ensure critical numeric parameters that are used as divisors (such as
SLIP_DELTA_THRESH and SLIP_LIMIT_RANGE) have minimum values greater than 0, and
ensure other numeric parameters are within acceptable ranges before assigning
them to their corresponding CFG properties.
|
Checking CI status and existing comments before proceeding. |
… with YAW_*, SLIP_DELTA_THRESH, US_REDUCTION, OS_BOOST, STEER_SMOOTH_MIN, TC_ENABLED)
Summary
Ground-up physics quality improvement replacing the slip-based countersteer approximation with direct car-state measurements.
What changed:
YAW_GAIN,YAW_DAMP) — opposes body rotation directly usingcar.localAngularVelocity.y(rad/s). Responds earlier than slip because yaw builds before wheels break away. ReplacesCOUNTERSTEER_GAIN/COUNTERSTEER_DAMP.SLIP_DELTA_THRESH,US_REDUCTION,OS_BOOST) — compares front vs rear slip to classify understeer/oversteer independently. Understeer tightens the driver authority clamp; oversteer amplifies yaw correction.car.brake > 0.4at speed) and reducesYAW_DAMPby 40% so corrections stay light on corner entry.STEER_SMOOTH_MIN) — stability metric derived from yaw rate + average slip drives blend betweenSTEER_SMOOTH(settled) andSTEER_SMOOTH_MIN(at the limit). Faster response exactly when it's needed.TC_ENABLED,TC_SLIP_THRESHOLD,TC_MAX_REDUCTION) — optional rear wheelspin detection viacar.wheelAngularSpeed[2..3]vs expected speed. Off by default.yawRate available: true/falseto confirmcar.localAngularVelocitypresence on first run.Breaking change:
COUNTERSTEER_GAINandCOUNTERSTEER_DAMPremoved from config and app. Preset files from v1.x will load without error (unknown keys are ignored) but the old self-steer behaviour is gone.Backwards-compatible path: Set
YAW_GAIN = 0→ yaw correction disabled → identical feel to v1.1 minus the slip-based self-steer.Files changed
MyGamepadFX/config.luaMyGamepadFX/lib.luayawRate,stageSlipClassify,stageYawDamp,stageAdaptiveSmooth,stageWheelspinMyGamepadFX/assist.luaapplyLiveCfg; add yawRate diagnosticMyGamepadFX_Config/app.luaMyGamepadFX_Config/manifest.iniMyGamepadFX/manifest.iniTest plan
YAW_GAIN = 0→ should feel identical to v1.1 (no yaw correction)oversteerFactor(visible in debug overlay)[MyGamepadFX] yawRate available: true/false