Replicating a physical grabbing system, and jittery movement for clients grabbing the object.

Hello everyone.
First of all, I use UE4.27 → can’t run UE5 on my potato pc :slight_smile:
I’m trying to make a multiplayer, physics-based grab system where objects move differently depending on their mass. I tried physics handles, but I couldn’t get them to where heavy objects can pivot and rotate when I pull them from a corner; they just move as a whole. So I decided to use constraints instead. Here is my setup:

Let’s define some things first:

“Anchor” is a component parented to a spring arm that uses control rotation; this is the component that the grabbed object is constrained to.

“Hook” is a component that is attached to the grabbed object at the point where it was grabbed. It is used to get an endpoint for a beam effect in Niagara, not important for the physics.

“Grab Component” is the component being grabbed.

  1. I do a trace locally, and if the object can be picked up, I call a grab event on the server:

  1. I pass the hit results I need to the server and constrain the grabbed component and the anchor on the server:

  1. In a RepNotify, I disable physics simulation on the clients and let the server simulate the grabbed component:

Everything works great, replicates well, except for one issue: when a client grabs an object and moves it, it flickers for that client only; the server and all other clients see it moving smoothly, but only the client who is grabbing the object sees the object jittering. And jitter happens only when the object is being moved, and especially when moved fast:

(it looks worse in-game than the video, probably because the video is only at 60fps)
I tried detaching the anchor from the spring arm and moving it on tick on the server, but it still flickers for the client who’s grabbing it.
I’d appreciate any help I could get. I’m running out of ideas on how to solve it.

Server needs to do its own trace and results.

This could make server override the values of local client , unlesss its listen server host, if there is no issue , then try detecting this trace on server and see how it looks

I was gonna do that to prevent cheating, but I was focused on getting the physics to work first, which the trace doesn’t affect.

It did make the trace on the server, but this doesn’t really have anything to do with the physics, and it is a listen server.
I think the problem is happening because of server-client latency: because the server is simulating the physics, and the physics constraint is driven by the anchor movement, which is driven by the client’s movement, by the time the physics simulation comes back from the server, the physics constraint target (the anchor) has already moved on the client, causing a sudden correction. I tried using a fake mesh that is interpolated to the real grabbed object’s position and rotation. It’s a lot better, but still not good. I’ll tweak it some more and see.

Update:
I use a fake static mesh that I spawn on the real grabbed object’s transform, and hide the real object only on the client who is doing the grabbing. Then, on tick, I send the transform of the real object from the server to the client doing the grabbing, and use that transform to drive the fake mesh, and the fake mesh ended up moving perfectly smoothly without any interpolation needed!

But I’m still not satisfied. What’s bugging me is that the result suggests that the client is indeed trying to move the grabbed object themselves, even though the server is constraining the grabbed object to its version of the client’s anchor and simulating the physics, so the grabbed object is expected to lag a little (to wait for the server to send back the simulation result), but not jitter. Jitter happens when the object’s transform is being set twice every frame to two slightly different transforms, but the client has physics simulation for the grabbed object OFF; so there is no apparent reason why the client would fight the server over the grabbed component’s transform.
So using the fake mesh is really just a workaround and not a solution.

Control rotation is replicated which handles the movement of the attached actor. That being said you’re always going to be fighting the server.

Each proxy should handle the movement based on the replicated control rotation. Don’t replicate movement of the actor, because the movement of the character is already replicated.

Update 2: I’ve looked into it a lot, and the only way I could find that works is to use a fake mesh on the client doing the grabbing. I made it much better now: no abundant variables or events that I can see, no jitter in the object, no jitter in the beam, everyone sees everything correctly, and multiple players can cooperate to carry a heavy object; it works great for my use case.
If anyone is struggling to make a replicated physics-driven grab system and wants to try this out, here is a walkthrough of how I did it:
The setup:
A spring arm component that uses control rotation. Disable collision tests for it, and set its arm length to zero (we only need its rotation, and here you might ask why not use the camera? For me, the camera is attached to a head socket, and even though the camera uses control rotation, the rotation of the camera itself doesn’t seem to replicate: for other clients, the rotation of the camera is locked to the rotation of the socket it’s attached to, so I used a spring arm instead)

A small, hidden static mesh component parented to the spring arm. Ignore its collision for all channels and set its collision type to physics only: this will work as an anchor for the physics constraint; we will constrain the grabbed object to this anchor.

If you want to have a beam for the grabbing, make a scene component, set it to replicate, and this will give us the endpoint of the beam.

And of course, a physics constraint component: put it in the same location as the anchor and parent it to the anchor. Check disable collisions, set all linear limits to free. Enable linear motors and angular motors (set the angular motors to twist and swing). And for both motors, set the position drive to 500 and the angular drive to 50.

And if you want to have a beam, add the Niagara system component (the system needs to take 3 vector inputs for beam start, beam end, and beam tangent). Set uncheck its auto-activate and make it hidden. Set its tick behavior to “use component tick group” and the component tick group to “post update work”, and you need to have the character tick set to POST PHYSICS; otherwise, the beam will lag behind the object.

Also, in the master blueprint of things you want to be able to grab, turn off simulate physics and disable gravity, and enable them on beginplay ONLY on the server using a ‘has authority’ switch. Make an array of characters (not actors, characters, for example: BP_FirstPersonCharacter), this will be the number of people holding that specific actor. And using the same interface you use to detect them in the line trace, add an interface call that passes you that array to use in the character blueprint. You can also add two more calls, which take in a character reference to add or remove from the array of “grabbers”, though you can operate on the array from the character. I personally chose to make add and remove calls instead.

Now onto the code:
The screenshots are all on Imgur with comments (some were too wide to put here without the compression making them unreadable):

https://imgur.com/a/ynUIWXj

I hope this helps someone, and sorry if I missed anything. :slight_smile: