Ragdoll Knockback Lag (Replication issue?)

Hello, when I apply knockback to a character while ragdolling them there is a noticeable lag to everyone that isn’t the person being ragdolled or the server. The ragdoll and knockback are both being handled on the server. I am using BodyVelocity for the knockback which I know is deprecated but I don’t think that is the issue as I’ve also tried to use ApplyImpulse() and gotten the same result. For the ragdoll, I’ve used two modules and gotten the same result:

and

Here are two recordings of what I mean.

This first one is between a client who isn’t getting ragdolled, and one that is

This second one is between a client who isn’t getting ragdolled and the server.

Things I’ve tried already that didn’t work are:

  • Setting the NetworkOwnership of the character getting ragdolled to the player who ragdolled them.
  • Setting the HumanoidRootPart to massless
  • Setting the RootJoint of the HumanoidRootPart to false when ragdolled then back to true when unragdolled.

I know making these ragdolls smoother is possible because of other games that have done it such as “The Strongest Battlegrounds”. This problem has had me stumped for a while so any and all help is appreciated. Thanks for reading!

2 Likes

Sorry for bumping this but this has been stumping me for a while. I’ve gotten a few different responses from people from different places: A few people have said it’s unsolvable as it’s an unavoidable lag caused by the server and clients communicating. Some other people have said I can make a clone of the player getting ragdolled, make the actual player invisible then apply the ragdoll effects to the clone. However, I’ve been advised against that because it’s a lot of extra work for a slight visual improvement. Some people have also told me to set the Network Ownership of the character getting ragdolled to nil (server). However, people have also advised me against this because it will give the player getting ragdolled a worse and laggier experience on their end. If those are the only things I’m able to do then I guess I’ll drop this problem here, but if there’s something else I can do i’d really appreciate someone letting me know. Again, thanks for reading.

I think the people who told you the lag you see is unavoidable are correct. The server runs at a lower Hz and must replicate the motion of the parts to all other clients. That’s why tweening parts on the server side is generally not recommended and looks choppy. Trying to get it smoother would need to be rendered individually for each client locally.

Yeah, this is the conclusion that I’m getting to as well, and now instead of trying to fully “eliminate” the lag. I want to try and minimize it as much as possible. I know that there is a way of doing this due to several games I’ve seen that have done it, here are clips of a few who have seemed to minimize it well:

The Strongest Battlegrounds

Z Battlegrounds

Sorcerer Battlegrounds

Do you have any idea how their ragdolls are that smooth or what I could do to make mine similar to theirs? As you can see in the videos, all three of the ragdolls have some sort of “hiccup”/stop at the start of the ragdoll but it’s a lot more minimal and consistent than mine. Mine also have a tendency to teleport to their final destination rather than moving there while theirs do not. Again any help is appreciated and thank you for reading.

What is the network ownership of the character while it’s rag dolled? It sounds like the ragdoll code sets the ownership to client so then there’s extra lag going from the server to the client back to the server then to the other clients.

Whether your ragdoll should be server or client controlled depends on how you’re using it and what you want to do (ex: if your ragdoll can be client controlled in some way it probably should be client sided). Having it server sided if it isn’t might fix your problem.

There potentially are more complex ways to handle knockback that artificially “remove” the delay.

For example, if another player knocks someone back you could artificially “give them ownership” by simulating the knockback on their client and replicating it to the client being knocked back (perhaps with some smoothing). This way the person doing the knockback would get immediate feedback.

Doing it on the server though is also a good middle solution between the person knocking back and the person being knocked back (though the best way depends on your game’s needs).

This is a fast read about some bits of network ownership:

I believe in those clips the Network Ownership of the dummy is the the server. I have already tried setting it to the player and gotten the same result. Multiple people have also advised me against setting the network ownership of the character being ragdolled to the player ragdolling them as it can cause the risk of exploiters.

1 Like

Yeah that’s generally a bad idea. What I meant was you can create a client copy of the ragdoll on the client who knocked back, then send the position of that with remote events back to the client who got knocked back.

Then on the client who got knocked back and got their ragdoll’s position, ragdoll their character and use a mover (AlignPosition or BodyPosition probably) to move the ragdoll to where the remote event says.

With some sanity checking of the remote events there isn’t much more risk of exploits compared to combat on Roblox in general.


If the ragdoll is server owned them I’m not entirely sure what the problem is from. In theory, the knockback should be entirely server controlled and the replication should happen equally fast for all the clients, including the one being knocked back. Perhaps there is some sort of ownership transfer delay?

Edit:
I didn’t see the clips before. I didn’t notice much delay though, maybe what’s there is just what’s expected from the replication? Transferring the ownership between the server and the client should set back the character slightly because the server’s info is outdated by the latency amount.

Yeah, the possible solution you gave me with the cloning is a solution that others have given me as well, the only reason I haven’t attempted to implement it yet is because I felt there was an easier and better way to accomplish this. However, it seems like I may just end up having to do that if I want the ragdolls to look smoother. And yes, the ragdoll and the knockback are both administered by the server which should make them server owned. In my clips, the delay/lag is a lot more noticeable on the one with the dummy rather than the one with the player. Sometimes the dummy will somewhat “smoothly” travel through the air, and other times its torso/hrp will move then the rest of the limbs will go and snap back in place with where the torso/hrp is. I didn’t see this inconsistency happening with the three other games I provided examples of so I felt there must be something that could be done to make it more consistent.

1 Like

Yeah I definitely noticed that a little too.

I’m pretty stumped as to what this is from. You could try setting the network ownership of all of the parts in the player, though that shouldn’t change any behavior. It’s just weird that all of the other limbs freeze momentarily besides the torso.

You could also try adding body velocities to all of the parts for the first bit of the ragdolling, or try using LinearVelocitys.

If none of those work and this is a significant problem, you could make the real character invisible and create a client sided copy of the character that moves to the position of the real character (you might need a new collision group for characters and fake characters so they can’t collide). That way the physics would be done on the client (and be smoother anyways).

I’ve already tried setting the network ownership of all of the parts inside the character being ragdolled to both the player ragdolling them and the server but it doesn’t really do anything. The only possible explanation I can think of as to why the torso is the only thing that moves sometimes is because I’m applying the knock back force to the hrp. I could try to apply force to all the parts in the character but I don’t know how I’d go about equally spreading out that force. As for linear velocity, I don’t think will make a difference (i could be wrong) because I’ve tried ApplyImpulse and it didn’t make a difference.

1 Like

Hey, im working on a combat system of my own, and i’ve ended up in the same problem as you. Have you figured anything out? The ragdoll in strongest battlegrounds seem flawless, and very smooth, there is a definitely a way to do this without enabling a major security breach. If you’d like we can talk further, just hit me a dm

Heres a video of my current ragdoll:

Unfortunately, I have not found a solution. Sorry for the lackluster reply but there really hasn’t been any updates or anything new I’ve found to try and fix this problem, sorry. If you ever find a solution of your own, I’d love it if you could share it with me. (And as for your comment on The Strongest Battlegrounds’ ragdoll, if you look carefully, they do have some sort of ragdoll delay. Even though it is a very smooth delay, it’s still there. Don’t know whether they intentionally put this delay or if it was an unavoidable one,
but it’s there.)

1 Like

Yea, there is a delay, but its still way smoother than the approach Im currently taking. I’ll see what I can find to solve this

1 Like

I know this post has been dead for a long time, but I just wanted to say that I think I’ve found a good solution, it basically requires creating a clone of the ragdoll on the client and making the actual ragdoll invisible. Then be sure to separate the clone’s collision layer to one that doesn’t interfere with the actual ragdoll. Then use BodyPosition and BodyOrientation (maxvelocity and maxforce at inf and responsiveness at 100 worked well for me). This in effect will interpolate the clones position to the real ragdolls position and will smooth out the otherwise laggy movement. This also helps prevent client de sync because it will always go to where the server says it should. It took me a while to figure this out so I hope it helps.

1 Like

Disregard what I said above, the real issue is that you might have is that your attachments are on the torso and not the humanoidrootpart which causes the replication delay.

1 Like

So this doesn’t work… ?

This text will be blurred

As I’ve mentioned somewhere else in this post, the solution @LeehamsonTheThird presented probably works but is pretty complicated for something I feel like has a better way of being done.

I think you guys might be misunderstanding what I am saying, what I mean is interpolating the joints is something I thought would work, but doesn’t as seen here:


you can tell that there is still jitter to it.

It wasn’t until I was messing around, attaching things to the character with ballsockets that I realized when you have an attachment on the humanoidrootpart it doesn’t look laggy, compared to having it on the attachment torso. Below are 2 examples of what I’m talking about

EXAMPLE 1 (NO PERCEIVED DELAY):


The attachment is parented to the humanoidrootpart (and the other one to the part)

EXAMPLE 2 (PERCEIVED DELAY):


The attachment is parented to the torso (and the other one to the part)

So the solution is not to create an over-the-top interpolation method, nor is it to clone the character. When you make the ragdoll just parent the attachment that is connected to the torso to the humanoidrootpart instead. If you’re doing everything correct, it should be that simple.

If you’re really confused, look at my code

function RagdollService:RagdollCharacter(char: Model, duration: number?)
    local StateService = Knit.GetService("StateService")
    if StateService:GetState(char) == "Ragdoll" then return end

--BEGIN IMPORTANT PART

    local plr = Players:GetPlayerFromCharacter(char) -- variable declaration stuff
    local hum = char:FindFirstChildOfClass("Humanoid")
    local hrp = char:FindFirstChild("HumanoidRootPart")
    if not hrp then return end

    RagdollService:EnableMotor6D(char, false) -- we just disable the motors
    RagdollService:BuildJoints(char) -- the important function
    RagdollService:EnableCollisionParts(char, true) -- just for looks

    hrp.CanCollide = false -- prevents ragdoll from spazing out

    if plr then 
        self.Client.Ragdoll:Fire(plr) -- this does what the else statement does on the client
    else
        hrp:SetNetworkOwner(nil)
        hum.AutoRotate = false
        hum.PlatformStand = true
    end

 --END IMPORTANT PART

    if not duration then return end
    if self._RagdollTimers[char] then coroutine.close(self._RagdollTimers[char]) end
    self._RagdollTimers[char] = coroutine.create(function()
        task.wait(duration)
        self:UnragdollCharacter(char)
    end)
    coroutine.resume(self._RagdollTimers[char])
end

here is the function RagdollService:BuildJoints()

function RagdollService:BuildJoints(char: Model)
    local hrp = char:FindFirstChild("HumanoidRootPart")

    for _,v in pairs(char:GetDescendants()) do
        if not v:IsA("BasePart") or v:FindFirstAncestorOfClass("Accessory") or v.Name == "Handle" or v.Name == "Torso" or v.Name == "HumanoidRootPart" then continue end

        if not RagdollData[v.Name] then continue end

        local a0: Attachment, a1: Attachment = Instance.new("Attachment"), Instance.new("Attachment")
        local joint: Constraint = ReplicatedStorage.RagdollJoints:FindFirstChild(RagdollData[v.Name].Joint):Clone()

        a0.Name = "RAGDOLL_ATTACHMENT"
        a0.Parent = v -- the other part
        a0.CFrame = RagdollData[v.Name].CFrame[2] -- cframe offset

        a1.Name = "RAGDOLL_ATTACHMENT"
        a1.Parent = hrp -- the literal most important part
        a1.CFrame = RagdollData[v.Name].CFrame[1] -- cframe offset

        joint.Name = "RAGDOLL_CONSTRAINT"
        joint.Parent = v
        joint.Attachment0 = a0
        joint.Attachment1 = a1

        v.Massless = true
    end
end

I hope this helps.

4 Likes

Can you send your uncopylocked .rblx please? Because I have an error in your code:

No, I recommend you learn what you’re reading before blindly copying and pasting.

1 Like