Skip to content

Add game speed controls to the embedded game window - #1346

Open
JoltedJon wants to merge 1 commit into
Redot-Engine:masterfrom
JoltedJon:speed-controls
Open

Add game speed controls to the embedded game window#1346
JoltedJon wants to merge 1 commit into
Redot-Engine:masterfrom
JoltedJon:speed-controls

Conversation

@JoltedJon

@JoltedJon JoltedJon commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Pulls in godotengine/godot#107273 from Godot as recommended by @joey-wheeler99

Summary by CodeRabbit

  • New Features

    • Added game-speed controls to the embedded game view, including selectable speed settings and a reset option.
    • Added support for user-configured time scaling and physics settings.
    • Time scaling now respects freezing and applies consistently to physics, video playback, and related runtime calculations.
  • Bug Fixes

    • Improved synchronization between editor game-speed controls and active game sessions.
    • Updated physics timing to use configured user settings for more consistent behavior.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

The engine now separates user and game time scales, derives effective timing values, and exposes user-scaled physics limits. The embedded game view adds speed controls and debugger messaging. Runtime systems use the new timing accessors.

Game Time-Scale Control

Layer / File(s) Summary
Engine timing model
core/config/engine.h, core/config/engine.cpp
Engine stores user and game scales separately. It derives effective timing values and exposes user-scaled physics settings.
Embedded game speed controls
editor/run/game_view_plugin.h, editor/run/game_view_plugin.cpp
GameView adds speed selection and reset controls. GameViewDebugger sends scale commands to active sessions and updates control state.
Debugger speed message handling
scene/debugger/scene_debugger.h, scene/debugger/scene_debugger.cpp
SceneDebugger validates speed_changed messages and applies the requested user time scale.
Runtime timing consumers
main/main.cpp, modules/jolt_physics/joints/jolt_hinge_joint_3d.cpp, scene/3d/velocity_tracker_3d.cpp, scene/gui/video_stream_player.cpp
Physics iteration, hinge estimation, velocity tracking, and video resampling use user-configured or effective timing values.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GameView
  participant GameViewDebugger
  participant SceneDebugger
  participant Engine
  participant Main
  GameView->>GameViewDebugger: select or reset game speed
  GameViewDebugger->>SceneDebugger: send speed_changed
  SceneDebugger->>Engine: set_user_time_scale
  Engine->>Engine: update effective time scale and physics limits
  Main->>Engine: read effective timing values
  Engine-->>Main: return user physics rate, effective scale, and step limit
Loading

Suggested reviewers: generalprotectionfault

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding game speed controls to the embedded game window.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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 `@editor/run/game_view_plugin.cpp`:
- Around line 626-632: Update GameView::_reset_time_scales() to reset
time_scale_index and refresh the speed buttons before the is_visible_in_tree()
early return. Keep debugger->reset_time_scale() behind the visibility guard so
the debugger message behavior remains unchanged.

In `@modules/jolt_physics/joints/jolt_hinge_joint_3d.cpp`:
- Around line 60-61: Update the hinge joint motor state so the requested
HINGE_JOINT_MOTOR_MAX_IMPULSE is retained separately from the derived
motor_max_torque. In set_param(), store the requested impulse and derive the
torque using the current effective step; when step_scaled changes in the physics
update path, recalculate motor_max_torque from that stored impulse. Ensure
get_param() continues converting the refreshed torque back to the requested
impulse consistently.

In `@scene/debugger/scene_debugger.cpp`:
- Around line 216-220: Update SceneDebugger::_msg_speed_changed to require
exactly one numeric argument and validate that the converted time-scale value is
finite before calling Engine::get_singleton()->set_user_time_scale. Return
ERR_INVALID_DATA for empty, extra, non-numeric, or non-finite input, while
preserving the existing successful update path for valid values.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d268355c-5a18-413b-8800-08cb535702ec

📥 Commits

Reviewing files that changed from the base of the PR and between c614335 and c258982.

📒 Files selected for processing (10)
  • core/config/engine.cpp
  • core/config/engine.h
  • editor/run/game_view_plugin.cpp
  • editor/run/game_view_plugin.h
  • main/main.cpp
  • modules/jolt_physics/joints/jolt_hinge_joint_3d.cpp
  • scene/3d/velocity_tracker_3d.cpp
  • scene/debugger/scene_debugger.cpp
  • scene/debugger/scene_debugger.h
  • scene/gui/video_stream_player.cpp

Comment on lines +626 to +632
void GameView::_reset_time_scales() {
if (!is_visible_in_tree()) {
return;
}
time_scale_index = DEFAULT_TIME_SCALE_INDEX;
debugger->reset_time_scale();
_update_speed_buttons();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset the UI state when GameView is hidden.

Line 627 returns before resetting time_scale_index or button state. If a game restarts while GameView is hidden, the new session uses 1.0× but the GameView can still show the previous speed.

Reset the local state and button state before the visibility guard. Keep the debugger message behind the guard if that behavior is intentional.

🤖 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 `@editor/run/game_view_plugin.cpp` around lines 626 - 632, Update
GameView::_reset_time_scales() to reset time_scale_index and refresh the speed
buttons before the is_visible_in_tree() early return. Keep
debugger->reset_time_scale() behind the visibility guard so the debugger message
behavior remains unchanged.

Comment on lines +60 to +61
const double step = 1.0 / engine->get_user_physics_ticks_per_second();
const double step_scaled = step * engine->get_effective_time_scale();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Refresh hinge motor torque when the effective step changes.

Line 61 now changes during a game-view speed update. set_param() converts HINGE_JOINT_MOTOR_MAX_IMPULSE to motor_max_torque only once at lines 246-249. A later speed change leaves that stored torque stale. get_param() then reports a different impulse value at lines 202-204.

Store the requested impulse and recalculate the Jolt torque limit when the effective physics step changes.

🤖 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 `@modules/jolt_physics/joints/jolt_hinge_joint_3d.cpp` around lines 60 - 61,
Update the hinge joint motor state so the requested
HINGE_JOINT_MOTOR_MAX_IMPULSE is retained separately from the derived
motor_max_torque. In set_param(), store the requested impulse and derive the
torque using the current effective step; when step_scaled changes in the physics
update path, recalculate motor_max_torque from that stored impulse. Ensure
get_param() continues converting the refreshed torque back to the requested
impulse consistently.

Comment on lines +216 to +220
Error SceneDebugger::_msg_speed_changed(const Array &p_args) {
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
double time_scale_user = p_args[0];
Engine::get_singleton()->set_user_time_scale(time_scale_user);
return OK;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate the time-scale value before applying it.

Line 217 only rejects an empty array. A non-finite value can reach Engine::set_user_time_scale() and propagate through runtime timing calculations.

Require one numeric, finite argument before updating the engine.

🤖 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 `@scene/debugger/scene_debugger.cpp` around lines 216 - 220, Update
SceneDebugger::_msg_speed_changed to require exactly one numeric argument and
validate that the converted time-scale value is finite before calling
Engine::get_singleton()->set_user_time_scale. Return ERR_INVALID_DATA for empty,
extra, non-numeric, or non-finite input, while preserving the existing
successful update path for valid values.

@joey-wheeler99

Copy link
Copy Markdown
Contributor

Thank you 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants