Ragdoll lags for other clients

Problem:

  • I’ve been working on a ragdoll system and the progress has been good. However, I’ve encountered some problems with the communication between server and clients.
  • For some reason when you ragdoll on high speed, it seems to freeze for a bit when viewed by another player. However this isn’t the case with the player being ragdolled.
  • And for note, this problem also happens outside of studio.

POV of ragdolled player:

POV of viewer:


image


Attempts to fix:

  • SetNetworkOwner(nil) - I’ve tried to set the network owner to nil, however all it did was make the player unable to ragdoll.
  • Messed with Motor6D’s - I’ve tried to mess around with Motor6D’s by disabling some parts but it just made the ragdoll more clunky and messed up.

Script:

-- Setup the humanoid for it to work with the ragdoll.
local function setupHumanoid(character: Model)
	local player = Players:GetPlayerFromCharacter(character)
	local humanoid: Humanoid = character:FindFirstChildOfClass("Humanoid")

	humanoid.RequiresNeck = false
	humanoid.BreakJointsOnDeath = false
	character:SetAttribute("Ragdoll", false)
end

-- Build the collision parts for the ragdoll.
local function buildCollisionParts(character: Model)
	for _, v in pairs(character:GetChildren()) do
		if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" then
			local part: BasePart = v:Clone()
			part.Name = "CollisionPart"

			part.Parent = v
			part.CanCollide = false
			part.Massless = true
			part.Transparency = 1
			part.Color = Color3.fromRGB(255, 255, 255)

			part:ClearAllChildren()

			local weld = Instance.new("Weld")
			weld.Parent = part
			weld.Part0 = v
			weld.Part1 = part

			if v.Name == "Head" or v.Name == "Torso" then
				part.Size = Vector3.one
			else
				part.Size = v.Size - Vector3.new(0.5, 0.25, 0.5)
				part.Position = v.Position - Vector3.new(0, 0.125, 0)
			end
		end
	end
end

-- Set the collision of the parts.
local function setCollisionParts(character: Model, boolean: boolean)
	if boolean then
		local Torso: BasePart = character:FindFirstChild("Torso")
		if Torso then
			Torso.CollisionGroup = collisionRagdollName
		end
	else
		local Torso: BasePart = character:FindFirstChild("Torso")
		if Torso then
			Torso.CollisionGroup = collisionDefaultName
		end
	end

	for _, v in pairs(character:GetChildren()) do
		if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" then
			v.CanCollide = not boolean
			v.CollisionPart.CanCollide = boolean
		end
	end
end

-- Build the joints for the ragdoll.
local function buildJoints(character: Model)
	local HRP = character:WaitForChild("HumanoidRootPart")

	for _, v in pairs(character: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 CFrameModule[v.Name] then
			continue
		end

		local a0: Attachment, a1: Attachment = Instance.new("Attachment"), Instance.new("Attachment")
		local joint: BallSocketConstraint = Instance.new("BallSocketConstraint")

		-- Add limitations to the ragdoll.
		joint.LimitsEnabled = true
		joint.TwistLimitsEnabled = true
		joint.MaxFrictionTorque = 10 -- This affects the stiffness.

		if v.Name == "Left Arm" or v.Name == "Right Arm" then
			joint.TwistLowerAngle = 140
			joint.TwistUpperAngle = -140
		end

		a0.Name = "RAGDOLL_ATTACHMENT"
		a0.Parent = v
		a0.CFrame = CFrameModule[v.Name].CFrame[2]

		a1.Name = "RAGDOLL_ATTACHMENT"
		a1.Parent = HRP
		a1.CFrame = CFrameModule[v.Name].CFrame[1]

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

		v.Massless = true
	end
end

-- Destroy the joints for the ragdoll.
local function destroyJoints(character: Model)
	local HRP = character:WaitForChild("HumanoidRootPart")
	HRP.Massless = false

	for _, v in pairs(character:GetDescendants()) do
		if v.Name == "RAGDOLL_ATTACHMENT" or v.Name == "RAGDOLL_CONSTRAINT" then
			v:Destroy()
		end

		if
			not v:IsA("BasePart")
			or v:FindFirstAncestorOfClass("Accessory")
			or v.Name == "Torso"
			or v.Name == "Head"
		then
			continue
		end
	end
end

-- Set whether the Motor6D is enabled or not.
local function setMotor6D(character: Model, boolean: boolean)
	for _, v in pairs(character:GetDescendants()) do
		if v.Name == "Handle" or v.Name == "RootJoint" or v.Name == "Neck" then
			continue
		end

		if v:IsA("Motor6D") then
			v.Enabled = boolean
		end
	end
end

-- || MAIN MODULE || --
local RagdollService = Knit.CreateService({
	Name = "RagdollService",
	Client = {
		Ragdoll = Knit.CreateSignal(),
		Unragdoll = Knit.CreateSignal(),
	},
})

function RagdollService.Client:RagdollSelf(player: Player)
	self.Server:RagdollCharacter(player.Character)
end

function RagdollService.Client:UnragdollSelf(player: Player)
	self.Server:UnragdollCharacter(player.Character)
end

-- Add cooldown for the RemoteEvent.
local currentTime = tick()
local ragdollCooldown = 1
local density = 7.5
function RagdollService:RagdollCharacter(character: Model)
	if tick() - currentTime >= ragdollCooldown then
		currentTime = tick()

		local player = Players:GetPlayerFromCharacter(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		local HRP = character:FindFirstChild("HumanoidRootPart")

		if not HRP then
			return
		end

		setMotor6D(character, false)
		buildJoints(character)
		setCollisionParts(character, true)
		character:SetAttribute("Ragdoll", true)
		
		for _, collisionParts in pairs(character:GetDescendants()) do 
			if collisionParts.Name == "CollisionPart" then
				collisionParts.Massless = false

				local currentProperties: PhysicalProperties = collisionParts.CurrentPhysicalProperties
				collisionParts.CustomPhysicalProperties = PhysicalProperties.new(density, currentProperties.Friction, currentProperties.Elasticity)
			end
		end

		if player then
			self.Client.Ragdoll:Fire(player)
		else
			HRP:SetNetworkOwner(nil)
			humanoid.AutoRotate = false
			humanoid.PlatformStand = true
		end
	end
end

Please tell me any ideas for solutions, or whether I should do my past attempts again. I will appreciate any help, thank you!

2 Likes

This is due to latency and there’s not much that can be done. You could try having every other client create their own versions of a ragdoll’s limbs, thus removing the need for the server to replicate that information to them.

2 Likes

Games like Advanced Euphoria Ragdoll - Roblox doesn’t have this issue though, and I’m pretty sure they don’t use client-sided ragdolls due to how everything replicates perfectly when I play with 2 accounts.

I have found the issue! It isn’t a problem with the engine, but my script itself. But I still appreciate the help :slight_smile: