Ropes are not processed by their node but in the NativeRopeServer class, which executes at the start of the physics frame, i.e. when the SceneTree.physics_frame signal runs.
Roughly sketched, the order looks like this:
SceneTree.physics_frame- Rope update
_physics_process()_draw()(ifqueue_redraw()was called in_physics_process())_process()_draw()(ifqueue_redraw()was called in_process())
This assumes that the FPS match the physics tick rate, which is usually locked at 60 FPS.
On a 144 Hz screen for example, it wouldn't match, resulting in more _process() frames than _physics_process().
NativeRopeServer provides a set of signals for fine-tuned execution order handling:
on_pre_updateon_pre_pre_updateon_post_updateon_post_post_update.
They get emitted just before/after rope updates.
SceneTree.physics_frameon_pre_pre_updateon_pre_update- Rope update
on_post_updateon_post_post_update
_physics_process()_process()
These signals are also used by various rope utilities like RopeAnchor, RopeHandle or RopeRendererLine2D to update the rope's properties or their own just before/after rope updates occur.
They use the normal pre and post signals, so it is safe to use pre_pre or post_post without interfering with them.
Updating the rope position in _process() or _physics_process() causes a one-frame delay because they run after the rope has already been updated.
Hence, the result is only visible in the next frame.
The workaround is to connect to NativeRopeServer.on_pre_pre_update and update the rope's position there.
It can essentially be treated as a kind of _physics_process() which runs just before rope updates.
You can take a look at the rope_pulling.tscn example.
The player node there uses the same approach.